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 13 static struct resource bcma_sflash_resource = { 14 .name = "bcma_sflash", 15 .start = BCMA_SFLASH, 16 .end = 0, 17 .flags = IORESOURCE_MEM | IORESOURCE_READONLY, 18 }; 19 20 struct platform_device bcma_sflash_dev = { 21 .name = "bcma_sflash", 22 .resource = &bcma_sflash_resource, 23 .num_resources = 1, 24 }; 25 26 struct bcma_sflash_tbl_e { 27 char *name; 28 u32 id; 29 u32 blocksize; 30 u16 numblocks; 31 }; 32 33 static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = { 34 { "", 0x14, 0x10000, 32, }, 35 { 0 }, 36 }; 37 38 static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = { 39 { 0 }, 40 }; 41 42 static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = { 43 { 0 }, 44 }; 45 46 static 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 */ 61 int 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