linux/arch/powerpc/platforms/powermac/nvram.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org)
   3 *
   4 *  This program is free software; you can redistribute it and/or
   5 *  modify it under the terms of the GNU General Public License
   6 *  as published by the Free Software Foundation; either version
   7 *  2 of the License, or (at your option) any later version.
   8 *
   9 *  Todo: - add support for the OF persistent properties
  10 */
  11#include <linux/export.h>
  12#include <linux/kernel.h>
  13#include <linux/stddef.h>
  14#include <linux/string.h>
  15#include <linux/nvram.h>
  16#include <linux/init.h>
  17#include <linux/delay.h>
  18#include <linux/errno.h>
  19#include <linux/adb.h>
  20#include <linux/pmu.h>
  21#include <linux/bootmem.h>
  22#include <linux/completion.h>
  23#include <linux/spinlock.h>
  24#include <asm/sections.h>
  25#include <asm/io.h>
  26#include <asm/system.h>
  27#include <asm/prom.h>
  28#include <asm/machdep.h>
  29#include <asm/nvram.h>
  30
  31#include "pmac.h"
  32
  33#define DEBUG
  34
  35#ifdef DEBUG
  36#define DBG(x...) printk(x)
  37#else
  38#define DBG(x...)
  39#endif
  40
  41#define NVRAM_SIZE              0x2000  /* 8kB of non-volatile RAM */
  42
  43#define CORE99_SIGNATURE        0x5a
  44#define CORE99_ADLER_START      0x14
  45
  46/* On Core99, nvram is either a sharp, a micron or an AMD flash */
  47#define SM_FLASH_STATUS_DONE    0x80
  48#define SM_FLASH_STATUS_ERR     0x38
  49
  50#define SM_FLASH_CMD_ERASE_CONFIRM      0xd0
  51#define SM_FLASH_CMD_ERASE_SETUP        0x20
  52#define SM_FLASH_CMD_RESET              0xff
  53#define SM_FLASH_CMD_WRITE_SETUP        0x40
  54#define SM_FLASH_CMD_CLEAR_STATUS       0x50
  55#define SM_FLASH_CMD_READ_STATUS        0x70
  56
  57/* CHRP NVRAM header */
  58struct chrp_header {
  59  u8            signature;
  60  u8            cksum;
  61  u16           len;
  62  char          name[12];
  63  u8            data[0];
  64};
  65
  66struct core99_header {
  67  struct chrp_header    hdr;
  68  u32                   adler;
  69  u32                   generation;
  70  u32                   reserved[2];
  71};
  72
  73/*
  74 * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
  75 */
  76static int nvram_naddrs;
  77static volatile unsigned char __iomem *nvram_data;
  78static int is_core_99;
  79static int core99_bank = 0;
  80static int nvram_partitions[3];
  81// XXX Turn that into a sem
  82static DEFINE_RAW_SPINLOCK(nv_lock);
  83
  84static int (*core99_write_bank)(int bank, u8* datas);
  85static int (*core99_erase_bank)(int bank);
  86
  87static char *nvram_image;
  88
  89
  90static unsigned char core99_nvram_read_byte(int addr)
  91{
  92        if (nvram_image == NULL)
  93                return 0xff;
  94        return nvram_image[addr];
  95}
  96
  97static void core99_nvram_write_byte(int addr, unsigned char val)
  98{
  99        if (nvram_image == NULL)
 100                return;
 101        nvram_image[addr] = val;
 102}
 103
 104static ssize_t core99_nvram_read(char *buf, size_t count, loff_t *index)
 105{
 106        int i;
 107
 108        if (nvram_image == NULL)
 109                return -ENODEV;
 110        if (*index > NVRAM_SIZE)
 111                return 0;
 112
 113        i = *index;
 114        if (i + count > NVRAM_SIZE)
 115                count = NVRAM_SIZE - i;
 116
 117        memcpy(buf, &nvram_image[i], count);
 118        *index = i + count;
 119        return count;
 120}
 121
 122static ssize_t core99_nvram_write(char *buf, size_t count, loff_t *index)
 123{
 124        int i;
 125
 126        if (nvram_image == NULL)
 127                return -ENODEV;
 128        if (*index > NVRAM_SIZE)
 129                return 0;
 130
 131        i = *index;
 132        if (i + count > NVRAM_SIZE)
 133                count = NVRAM_SIZE - i;
 134
 135        memcpy(&nvram_image[i], buf, count);
 136        *index = i + count;
 137        return count;
 138}
 139
 140static ssize_t core99_nvram_size(void)
 141{
 142        if (nvram_image == NULL)
 143                return -ENODEV;
 144        return NVRAM_SIZE;
 145}
 146
 147#ifdef CONFIG_PPC32
 148static volatile unsigned char __iomem *nvram_addr;
 149static int nvram_mult;
 150
 151static unsigned char direct_nvram_read_byte(int addr)
 152{
 153        return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]);
 154}
 155
 156static void direct_nvram_write_byte(int addr, unsigned char val)
 157{
 158        out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val);
 159}
 160
 161
 162static unsigned char indirect_nvram_read_byte(int addr)
 163{
 164        unsigned char val;
 165        unsigned long flags;
 166
 167        raw_spin_lock_irqsave(&nv_lock, flags);
 168        out_8(nvram_addr, addr >> 5);
 169        val = in_8(&nvram_data[(addr & 0x1f) << 4]);
 170        raw_spin_unlock_irqrestore(&nv_lock, flags);
 171
 172        return val;
 173}
 174
 175static void indirect_nvram_write_byte(int addr, unsigned char val)
 176{
 177        unsigned long flags;
 178
 179        raw_spin_lock_irqsave(&nv_lock, flags);
 180        out_8(nvram_addr, addr >> 5);
 181        out_8(&nvram_data[(addr & 0x1f) << 4], val);
 182        raw_spin_unlock_irqrestore(&nv_lock, flags);
 183}
 184
 185
 186#ifdef CONFIG_ADB_PMU
 187
 188static void pmu_nvram_complete(struct adb_request *req)
 189{
 190        if (req->arg)
 191                complete((struct completion *)req->arg);
 192}
 193
 194static unsigned char pmu_nvram_read_byte(int addr)
 195{
 196        struct adb_request req;
 197        DECLARE_COMPLETION_ONSTACK(req_complete);
 198        
 199        req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
 200        if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
 201                        (addr >> 8) & 0xff, addr & 0xff))
 202                return 0xff;
 203        if (system_state == SYSTEM_RUNNING)
 204                wait_for_completion(&req_complete);
 205        while (!req.complete)
 206                pmu_poll();
 207        return req.reply[0];
 208}
 209
 210static void pmu_nvram_write_byte(int addr, unsigned char val)
 211{
 212        struct adb_request req;
 213        DECLARE_COMPLETION_ONSTACK(req_complete);
 214        
 215        req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
 216        if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
 217                        (addr >> 8) & 0xff, addr & 0xff, val))
 218                return;
 219        if (system_state == SYSTEM_RUNNING)
 220                wait_for_completion(&req_complete);
 221        while (!req.complete)
 222                pmu_poll();
 223}
 224
 225#endif /* CONFIG_ADB_PMU */
 226#endif /* CONFIG_PPC32 */
 227
 228static u8 chrp_checksum(struct chrp_header* hdr)
 229{
 230        u8 *ptr;
 231        u16 sum = hdr->signature;
 232        for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
 233                sum += *ptr;
 234        while (sum > 0xFF)
 235                sum = (sum & 0xFF) + (sum>>8);
 236        return sum;
 237}
 238
 239static u32 core99_calc_adler(u8 *buffer)
 240{
 241        int cnt;
 242        u32 low, high;
 243
 244        buffer += CORE99_ADLER_START;
 245        low = 1;
 246        high = 0;
 247        for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
 248                if ((cnt % 5000) == 0) {
 249                        high  %= 65521UL;
 250                        high %= 65521UL;
 251                }
 252                low += buffer[cnt];
 253                high += low;
 254        }
 255        low  %= 65521UL;
 256        high %= 65521UL;
 257
 258        return (high << 16) | low;
 259}
 260
 261static u32 core99_check(u8* datas)
 262{
 263        struct core99_header* hdr99 = (struct core99_header*)datas;
 264
 265        if (hdr99->hdr.signature != CORE99_SIGNATURE) {
 266                DBG("Invalid signature\n");
 267                return 0;
 268        }
 269        if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
 270                DBG("Invalid checksum\n");
 271                return 0;
 272        }
 273        if (hdr99->adler != core99_calc_adler(datas)) {
 274                DBG("Invalid adler\n");
 275                return 0;
 276        }
 277        return hdr99->generation;
 278}
 279
 280static int sm_erase_bank(int bank)
 281{
 282        int stat, i;
 283        unsigned long timeout;
 284
 285        u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
 286
 287        DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
 288
 289        out_8(base, SM_FLASH_CMD_ERASE_SETUP);
 290        out_8(base, SM_FLASH_CMD_ERASE_CONFIRM);
 291        timeout = 0;
 292        do {
 293                if (++timeout > 1000000) {
 294                        printk(KERN_ERR "nvram: Sharp/Micron flash erase timeout !\n");
 295                        break;
 296                }
 297                out_8(base, SM_FLASH_CMD_READ_STATUS);
 298                stat = in_8(base);
 299        } while (!(stat & SM_FLASH_STATUS_DONE));
 300
 301        out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
 302        out_8(base, SM_FLASH_CMD_RESET);
 303
 304        for (i=0; i<NVRAM_SIZE; i++)
 305                if (base[i] != 0xff) {
 306                        printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
 307                        return -ENXIO;
 308                }
 309        return 0;
 310}
 311
 312static int sm_write_bank(int bank, u8* datas)
 313{
 314        int i, stat = 0;
 315        unsigned long timeout;
 316
 317        u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
 318
 319        DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
 320
 321        for (i=0; i<NVRAM_SIZE; i++) {
 322                out_8(base+i, SM_FLASH_CMD_WRITE_SETUP);
 323                udelay(1);
 324                out_8(base+i, datas[i]);
 325                timeout = 0;
 326                do {
 327                        if (++timeout > 1000000) {
 328                                printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n");
 329                                break;
 330                        }
 331                        out_8(base, SM_FLASH_CMD_READ_STATUS);
 332                        stat = in_8(base);
 333                } while (!(stat & SM_FLASH_STATUS_DONE));
 334                if (!(stat & SM_FLASH_STATUS_DONE))
 335                        break;
 336        }
 337        out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
 338        out_8(base, SM_FLASH_CMD_RESET);
 339        for (i=0; i<NVRAM_SIZE; i++)
 340                if (base[i] != datas[i]) {
 341                        printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
 342                        return -ENXIO;
 343                }
 344        return 0;
 345}
 346
 347static int amd_erase_bank(int bank)
 348{
 349        int i, stat = 0;
 350        unsigned long timeout;
 351
 352        u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
 353
 354        DBG("nvram: AMD Erasing bank %d...\n", bank);
 355
 356        /* Unlock 1 */
 357        out_8(base+0x555, 0xaa);
 358        udelay(1);
 359        /* Unlock 2 */
 360        out_8(base+0x2aa, 0x55);
 361        udelay(1);
 362
 363        /* Sector-Erase */
 364        out_8(base+0x555, 0x80);
 365        udelay(1);
 366        out_8(base+0x555, 0xaa);
 367        udelay(1);
 368        out_8(base+0x2aa, 0x55);
 369        udelay(1);
 370        out_8(base, 0x30);
 371        udelay(1);
 372
 373        timeout = 0;
 374        do {
 375                if (++timeout > 1000000) {
 376                        printk(KERN_ERR "nvram: AMD flash erase timeout !\n");
 377                        break;
 378                }
 379                stat = in_8(base) ^ in_8(base);
 380        } while (stat != 0);
 381        
 382        /* Reset */
 383        out_8(base, 0xf0);
 384        udelay(1);
 385        
 386        for (i=0; i<NVRAM_SIZE; i++)
 387                if (base[i] != 0xff) {
 388                        printk(KERN_ERR "nvram: AMD flash erase failed !\n");
 389                        return -ENXIO;
 390                }
 391        return 0;
 392}
 393
 394static int amd_write_bank(int bank, u8* datas)
 395{
 396        int i, stat = 0;
 397        unsigned long timeout;
 398
 399        u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
 400
 401        DBG("nvram: AMD Writing bank %d...\n", bank);
 402
 403        for (i=0; i<NVRAM_SIZE; i++) {
 404                /* Unlock 1 */
 405                out_8(base+0x555, 0xaa);
 406                udelay(1);
 407                /* Unlock 2 */
 408                out_8(base+0x2aa, 0x55);
 409                udelay(1);
 410
 411                /* Write single word */
 412                out_8(base+0x555, 0xa0);
 413                udelay(1);
 414                out_8(base+i, datas[i]);
 415                
 416                timeout = 0;
 417                do {
 418                        if (++timeout > 1000000) {
 419                                printk(KERN_ERR "nvram: AMD flash write timeout !\n");
 420                                break;
 421                        }
 422                        stat = in_8(base) ^ in_8(base);
 423                } while (stat != 0);
 424                if (stat != 0)
 425                        break;
 426        }
 427
 428        /* Reset */
 429        out_8(base, 0xf0);
 430        udelay(1);
 431
 432        for (i=0; i<NVRAM_SIZE; i++)
 433                if (base[i] != datas[i]) {
 434                        printk(KERN_ERR "nvram: AMD flash write failed !\n");
 435                        return -ENXIO;
 436                }
 437        return 0;
 438}
 439
 440static void __init lookup_partitions(void)
 441{
 442        u8 buffer[17];
 443        int i, offset;
 444        struct chrp_header* hdr;
 445
 446        if (pmac_newworld) {
 447                nvram_partitions[pmac_nvram_OF] = -1;
 448                nvram_partitions[pmac_nvram_XPRAM] = -1;
 449                nvram_partitions[pmac_nvram_NR] = -1;
 450                hdr = (struct chrp_header *)buffer;
 451
 452                offset = 0;
 453                buffer[16] = 0;
 454                do {
 455                        for (i=0;i<16;i++)
 456                                buffer[i] = ppc_md.nvram_read_val(offset+i);
 457                        if (!strcmp(hdr->name, "common"))
 458                                nvram_partitions[pmac_nvram_OF] = offset + 0x10;
 459                        if (!strcmp(hdr->name, "APL,MacOS75")) {
 460                                nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
 461                                nvram_partitions[pmac_nvram_NR] = offset + 0x110;
 462                        }
 463                        offset += (hdr->len * 0x10);
 464                } while(offset < NVRAM_SIZE);
 465        } else {
 466                nvram_partitions[pmac_nvram_OF] = 0x1800;
 467                nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
 468                nvram_partitions[pmac_nvram_NR] = 0x1400;
 469        }
 470        DBG("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
 471        DBG("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
 472        DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
 473}
 474
 475static void core99_nvram_sync(void)
 476{
 477        struct core99_header* hdr99;
 478        unsigned long flags;
 479
 480        if (!is_core_99 || !nvram_data || !nvram_image)
 481                return;
 482
 483        raw_spin_lock_irqsave(&nv_lock, flags);
 484        if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
 485                NVRAM_SIZE))
 486                goto bail;
 487
 488        DBG("Updating nvram...\n");
 489
 490        hdr99 = (struct core99_header*)nvram_image;
 491        hdr99->generation++;
 492        hdr99->hdr.signature = CORE99_SIGNATURE;
 493        hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
 494        hdr99->adler = core99_calc_adler(nvram_image);
 495        core99_bank = core99_bank ? 0 : 1;
 496        if (core99_erase_bank)
 497                if (core99_erase_bank(core99_bank)) {
 498                        printk("nvram: Error erasing bank %d\n", core99_bank);
 499                        goto bail;
 500                }
 501        if (core99_write_bank)
 502                if (core99_write_bank(core99_bank, nvram_image))
 503                        printk("nvram: Error writing bank %d\n", core99_bank);
 504 bail:
 505        raw_spin_unlock_irqrestore(&nv_lock, flags);
 506
 507#ifdef DEBUG
 508        mdelay(2000);
 509#endif
 510}
 511
 512static int __init core99_nvram_setup(struct device_node *dp, unsigned long addr)
 513{
 514        int i;
 515        u32 gen_bank0, gen_bank1;
 516
 517        if (nvram_naddrs < 1) {
 518                printk(KERN_ERR "nvram: no address\n");
 519                return -EINVAL;
 520        }
 521        nvram_image = alloc_bootmem(NVRAM_SIZE);
 522        if (nvram_image == NULL) {
 523                printk(KERN_ERR "nvram: can't allocate ram image\n");
 524                return -ENOMEM;
 525        }
 526        nvram_data = ioremap(addr, NVRAM_SIZE*2);
 527        nvram_naddrs = 1; /* Make sure we get the correct case */
 528
 529        DBG("nvram: Checking bank 0...\n");
 530
 531        gen_bank0 = core99_check((u8 *)nvram_data);
 532        gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
 533        core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
 534
 535        DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
 536        DBG("nvram: Active bank is: %d\n", core99_bank);
 537
 538        for (i=0; i<NVRAM_SIZE; i++)
 539                nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
 540
 541        ppc_md.nvram_read_val   = core99_nvram_read_byte;
 542        ppc_md.nvram_write_val  = core99_nvram_write_byte;
 543        ppc_md.nvram_read       = core99_nvram_read;
 544        ppc_md.nvram_write      = core99_nvram_write;
 545        ppc_md.nvram_size       = core99_nvram_size;
 546        ppc_md.nvram_sync       = core99_nvram_sync;
 547        ppc_md.machine_shutdown = core99_nvram_sync;
 548        /* 
 549         * Maybe we could be smarter here though making an exclusive list
 550         * of known flash chips is a bit nasty as older OF didn't provide us
 551         * with a useful "compatible" entry. A solution would be to really
 552         * identify the chip using flash id commands and base ourselves on
 553         * a list of known chips IDs
 554         */
 555        if (of_device_is_compatible(dp, "amd-0137")) {
 556                core99_erase_bank = amd_erase_bank;
 557                core99_write_bank = amd_write_bank;
 558        } else {
 559                core99_erase_bank = sm_erase_bank;
 560                core99_write_bank = sm_write_bank;
 561        }
 562        return 0;
 563}
 564
 565int __init pmac_nvram_init(void)
 566{
 567        struct device_node *dp;
 568        struct resource r1, r2;
 569        unsigned int s1 = 0, s2 = 0;
 570        int err = 0;
 571
 572        nvram_naddrs = 0;
 573
 574        dp = of_find_node_by_name(NULL, "nvram");
 575        if (dp == NULL) {
 576                printk(KERN_ERR "Can't find NVRAM device\n");
 577                return -ENODEV;
 578        }
 579
 580        /* Try to obtain an address */
 581        if (of_address_to_resource(dp, 0, &r1) == 0) {
 582                nvram_naddrs = 1;
 583                s1 = resource_size(&r1);
 584                if (of_address_to_resource(dp, 1, &r2) == 0) {
 585                        nvram_naddrs = 2;
 586                        s2 = resource_size(&r2);
 587                }
 588        }
 589
 590        is_core_99 = of_device_is_compatible(dp, "nvram,flash");
 591        if (is_core_99) {
 592                err = core99_nvram_setup(dp, r1.start);
 593                goto bail;
 594        }
 595
 596#ifdef CONFIG_PPC32
 597        if (machine_is(chrp) && nvram_naddrs == 1) {
 598                nvram_data = ioremap(r1.start, s1);
 599                nvram_mult = 1;
 600                ppc_md.nvram_read_val   = direct_nvram_read_byte;
 601                ppc_md.nvram_write_val  = direct_nvram_write_byte;
 602        } else if (nvram_naddrs == 1) {
 603                nvram_data = ioremap(r1.start, s1);
 604                nvram_mult = (s1 + NVRAM_SIZE - 1) / NVRAM_SIZE;
 605                ppc_md.nvram_read_val   = direct_nvram_read_byte;
 606                ppc_md.nvram_write_val  = direct_nvram_write_byte;
 607        } else if (nvram_naddrs == 2) {
 608                nvram_addr = ioremap(r1.start, s1);
 609                nvram_data = ioremap(r2.start, s2);
 610                ppc_md.nvram_read_val   = indirect_nvram_read_byte;
 611                ppc_md.nvram_write_val  = indirect_nvram_write_byte;
 612        } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
 613#ifdef CONFIG_ADB_PMU
 614                nvram_naddrs = -1;
 615                ppc_md.nvram_read_val   = pmu_nvram_read_byte;
 616                ppc_md.nvram_write_val  = pmu_nvram_write_byte;
 617#endif /* CONFIG_ADB_PMU */
 618        } else {
 619                printk(KERN_ERR "Incompatible type of NVRAM\n");
 620                err = -ENXIO;
 621        }
 622#endif /* CONFIG_PPC32 */
 623bail:
 624        of_node_put(dp);
 625        if (err == 0)
 626                lookup_partitions();
 627        return err;
 628}
 629
 630int pmac_get_partition(int partition)
 631{
 632        return nvram_partitions[partition];
 633}
 634
 635u8 pmac_xpram_read(int xpaddr)
 636{
 637        int offset = pmac_get_partition(pmac_nvram_XPRAM);
 638
 639        if (offset < 0 || xpaddr < 0 || xpaddr > 0x100)
 640                return 0xff;
 641
 642        return ppc_md.nvram_read_val(xpaddr + offset);
 643}
 644
 645void pmac_xpram_write(int xpaddr, u8 data)
 646{
 647        int offset = pmac_get_partition(pmac_nvram_XPRAM);
 648
 649        if (offset < 0 || xpaddr < 0 || xpaddr > 0x100)
 650                return;
 651
 652        ppc_md.nvram_write_val(xpaddr + offset, data);
 653}
 654
 655EXPORT_SYMBOL(pmac_get_partition);
 656EXPORT_SYMBOL(pmac_xpram_read);
 657EXPORT_SYMBOL(pmac_xpram_write);
 658