diff options
Diffstat (limited to 'drivers/bcma/driver_chipcommon_sflash.c')
-rw-r--r-- | drivers/bcma/driver_chipcommon_sflash.c | 123 |
1 files changed, 120 insertions, 3 deletions
diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c index 6e157a58a1d7..2c4eec2ca5a0 100644 --- a/drivers/bcma/driver_chipcommon_sflash.c +++ b/drivers/bcma/driver_chipcommon_sflash.c | |||
@@ -5,15 +5,132 @@ | |||
5 | * Licensed under the GNU/GPL. See COPYING for details. | 5 | * Licensed under the GNU/GPL. See COPYING for details. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/platform_device.h> | ||
8 | #include <linux/bcma/bcma.h> | 9 | #include <linux/bcma/bcma.h> |
9 | #include <linux/bcma/bcma_driver_chipcommon.h> | ||
10 | #include <linux/delay.h> | ||
11 | 10 | ||
12 | #include "bcma_private.h" | 11 | #include "bcma_private.h" |
13 | 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 | |||
14 | /* Initialize serial flash access */ | 60 | /* Initialize serial flash access */ |
15 | int bcma_sflash_init(struct bcma_drv_cc *cc) | 61 | int bcma_sflash_init(struct bcma_drv_cc *cc) |
16 | { | 62 | { |
17 | bcma_err(cc->core->bus, "Serial flash support is broken\n"); | 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 | |||
18 | return 0; | 135 | return 0; |
19 | } | 136 | } |