linux/drivers/bcma/driver_chipcommon_sflash.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific AMBA
   3 * ChipCommon serial flash interface
   4 *
   5 * Licensed under the GNU/GPL. See COPYING for details.
   6 */
   7
   8#include <linux/platform_device.h>
   9#include <linux/bcma/bcma.h>
  10
  11#include "bcma_private.h"
  12
  13static struct resource bcma_sflash_resource = {
  14        .name   = "bcma_sflash",
  15        .start  = BCMA_SFLASH,
  16        .end    = 0,
  17        .flags  = IORESOURCE_MEM | IORESOURCE_READONLY,
  18};
  19
  20struct platform_device bcma_sflash_dev = {
  21        .name           = "bcma_sflash",
  22        .resource       = &bcma_sflash_resource,
  23        .num_resources  = 1,
  24};
  25
  26struct bcma_sflash_tbl_e {
  27        char *name;
  28        u32 id;
  29        u32 blocksize;
  30        u16 numblocks;
  31};
  32
  33static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
  34        { "", 0x14, 0x10000, 32, },
  35        { 0 },
  36};
  37
  38static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
  39        { 0 },
  40};
  41
  42static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
  43        { 0 },
  44};
  45
  46static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
  47{
  48        int i;
  49        bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
  50                        BCMA_CC_FLASHCTL_START | opcode);
  51        for (i = 0; i < 1000; i++) {
  52                if (!(bcma_cc_read32(cc, BCMA_CC_FLASHCTL) &
  53                      BCMA_CC_FLASHCTL_BUSY))
  54                        return;
  55                cpu_relax();
  56        }
  57        bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
  58}
  59
  60/* Initialize serial flash access */
  61int bcma_sflash_init(struct bcma_drv_cc *cc)
  62{
  63        struct bcma_bus *bus = cc->core->bus;
  64        struct bcma_sflash *sflash = &cc->sflash;
  65        struct bcma_sflash_tbl_e *e;
  66        u32 id, id2;
  67
  68        switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
  69        case BCMA_CC_FLASHT_STSER:
  70                bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP);
  71
  72                bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0);
  73                bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
  74                id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
  75
  76                bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1);
  77                bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
  78                id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
  79
  80                switch (id) {
  81                case 0xbf:
  82                        for (e = bcma_sflash_sst_tbl; e->name; e++) {
  83                                if (e->id == id2)
  84                                        break;
  85                        }
  86                        break;
  87                default:
  88                        for (e = bcma_sflash_st_tbl; e->name; e++) {
  89                                if (e->id == id)
  90                                        break;
  91                        }
  92                        break;
  93                }
  94                if (!e->name) {
  95                        bcma_err(bus, "Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", id, id2);
  96                        return -ENOTSUPP;
  97                }
  98
  99                break;
 100        case BCMA_CC_FLASHT_ATSER:
 101                bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
 102                id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
 103
 104                for (e = bcma_sflash_at_tbl; e->name; e++) {
 105                        if (e->id == id)
 106                                break;
 107                }
 108                if (!e->name) {
 109                        bcma_err(bus, "Unsupported Atmel serial flash (id: 0x%X)\n", id);
 110                        return -ENOTSUPP;
 111                }
 112
 113                break;
 114        default:
 115                bcma_err(bus, "Unsupported flash type\n");
 116                return -ENOTSUPP;
 117        }
 118
 119        sflash->window = BCMA_SFLASH;
 120        sflash->blocksize = e->blocksize;
 121        sflash->numblocks = e->numblocks;
 122        sflash->size = sflash->blocksize * sflash->numblocks;
 123        sflash->present = true;
 124
 125        bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
 126                  e->name, sflash->size / 1024, sflash->blocksize,
 127                  sflash->numblocks);
 128
 129        /* Prepare platform device, but don't register it yet. It's too early,
 130         * malloc (required by device_private_init) is not available yet. */
 131        bcma_sflash_dev.resource[0].end = bcma_sflash_dev.resource[0].start +
 132                                          sflash->size;
 133        bcma_sflash_dev.dev.platform_data = sflash;
 134
 135        return 0;
 136}
 137