diff options
author | Sean MacLennan <smaclennan@pikatech.com> | 2008-05-20 09:28:52 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2008-05-29 08:06:56 -0400 |
commit | 4ebef31fa6e013e5cd3d4522e6018eb6d55046be (patch) | |
tree | 78843ac145fe2e4c18de4809c2609df474068c88 /arch/powerpc/platforms/44x | |
parent | 0393cb615f369b6ea0e636dd4d1e25675657dc75 (diff) |
[POWERPC] PIKA Warp: Update platform code to support Rev B boards
* Switched from 64M NOR/64M NAND to 4M NOR/256M NAND.
* Full DTM support including critical temperature.
* Added POST information.
* Removed LED function, moved to new LED driver.
* Moved ad7414 to new style I2C initialization.
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/powerpc/platforms/44x')
-rw-r--r-- | arch/powerpc/platforms/44x/warp-nand.c | 49 | ||||
-rw-r--r-- | arch/powerpc/platforms/44x/warp.c | 293 |
2 files changed, 280 insertions, 62 deletions
diff --git a/arch/powerpc/platforms/44x/warp-nand.c b/arch/powerpc/platforms/44x/warp-nand.c index 9150318cfc56..d293c702e734 100644 --- a/arch/powerpc/platforms/44x/warp-nand.c +++ b/arch/powerpc/platforms/44x/warp-nand.c | |||
@@ -11,8 +11,10 @@ | |||
11 | #include <linux/mtd/partitions.h> | 11 | #include <linux/mtd/partitions.h> |
12 | #include <linux/mtd/nand.h> | 12 | #include <linux/mtd/nand.h> |
13 | #include <linux/mtd/ndfc.h> | 13 | #include <linux/mtd/ndfc.h> |
14 | #include <linux/of.h> | ||
14 | #include <asm/machdep.h> | 15 | #include <asm/machdep.h> |
15 | 16 | ||
17 | |||
16 | #ifdef CONFIG_MTD_NAND_NDFC | 18 | #ifdef CONFIG_MTD_NAND_NDFC |
17 | 19 | ||
18 | #define CS_NAND_0 1 /* use chip select 1 for NAND device 0 */ | 20 | #define CS_NAND_0 1 /* use chip select 1 for NAND device 0 */ |
@@ -35,13 +37,23 @@ static struct mtd_partition nand_parts[] = { | |||
35 | { | 37 | { |
36 | .name = "root", | 38 | .name = "root", |
37 | .offset = 0x0200000, | 39 | .offset = 0x0200000, |
38 | .size = 0x3400000 | 40 | .size = 0x3E00000 |
41 | }, | ||
42 | { | ||
43 | .name = "persistent", | ||
44 | .offset = 0x4000000, | ||
45 | .size = 0x4000000 | ||
39 | }, | 46 | }, |
40 | { | 47 | { |
41 | .name = "user", | 48 | .name = "persistent1", |
42 | .offset = 0x3600000, | 49 | .offset = 0x8000000, |
43 | .size = 0x0A00000 | 50 | .size = 0x4000000 |
44 | }, | 51 | }, |
52 | { | ||
53 | .name = "persistent2", | ||
54 | .offset = 0xC000000, | ||
55 | .size = 0x4000000 | ||
56 | } | ||
45 | }; | 57 | }; |
46 | 58 | ||
47 | struct ndfc_controller_settings warp_ndfc_settings = { | 59 | struct ndfc_controller_settings warp_ndfc_settings = { |
@@ -67,19 +79,15 @@ static struct platform_device warp_ndfc_device = { | |||
67 | .resource = &warp_ndfc, | 79 | .resource = &warp_ndfc, |
68 | }; | 80 | }; |
69 | 81 | ||
70 | static struct nand_ecclayout nand_oob_16 = { | 82 | /* Do NOT set the ecclayout: let it default so it is correct for both |
71 | .eccbytes = 3, | 83 | * 64M and 256M flash chips. |
72 | .eccpos = { 0, 1, 2, 3, 6, 7 }, | 84 | */ |
73 | .oobfree = { {.offset = 8, .length = 16} } | ||
74 | }; | ||
75 | |||
76 | static struct platform_nand_chip warp_nand_chip0 = { | 85 | static struct platform_nand_chip warp_nand_chip0 = { |
77 | .nr_chips = 1, | 86 | .nr_chips = 1, |
78 | .chip_offset = CS_NAND_0, | 87 | .chip_offset = CS_NAND_0, |
79 | .nr_partitions = ARRAY_SIZE(nand_parts), | 88 | .nr_partitions = ARRAY_SIZE(nand_parts), |
80 | .partitions = nand_parts, | 89 | .partitions = nand_parts, |
81 | .chip_delay = 50, | 90 | .chip_delay = 20, |
82 | .ecclayout = &nand_oob_16, | ||
83 | .priv = &warp_chip0_settings, | 91 | .priv = &warp_chip0_settings, |
84 | }; | 92 | }; |
85 | 93 | ||
@@ -96,6 +104,23 @@ static struct platform_device warp_nand_device = { | |||
96 | 104 | ||
97 | static int warp_setup_nand_flash(void) | 105 | static int warp_setup_nand_flash(void) |
98 | { | 106 | { |
107 | struct device_node *np; | ||
108 | |||
109 | /* Try to detect a rev A based on NOR size. */ | ||
110 | np = of_find_compatible_node(NULL, NULL, "cfi-flash"); | ||
111 | if (np) { | ||
112 | struct property *pp; | ||
113 | |||
114 | pp = of_find_property(np, "reg", NULL); | ||
115 | if (pp && (pp->length == 12)) { | ||
116 | u32 *v = pp->value; | ||
117 | if (v[2] == 0x4000000) | ||
118 | /* Rev A = 64M NAND */ | ||
119 | warp_nand_chip0.nr_partitions = 2; | ||
120 | } | ||
121 | of_node_put(np); | ||
122 | } | ||
123 | |||
99 | platform_device_register(&warp_ndfc_device); | 124 | platform_device_register(&warp_ndfc_device); |
100 | platform_device_register(&warp_nand_device); | 125 | platform_device_register(&warp_nand_device); |
101 | 126 | ||
diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index 39cf6150a72b..9565995cba7f 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c | |||
@@ -12,6 +12,9 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/of_platform.h> | 13 | #include <linux/of_platform.h> |
14 | #include <linux/kthread.h> | 14 | #include <linux/kthread.h> |
15 | #include <linux/i2c.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/delay.h> | ||
15 | 18 | ||
16 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
17 | #include <asm/prom.h> | 20 | #include <asm/prom.h> |
@@ -27,6 +30,18 @@ static __initdata struct of_device_id warp_of_bus[] = { | |||
27 | {}, | 30 | {}, |
28 | }; | 31 | }; |
29 | 32 | ||
33 | static __initdata struct i2c_board_info warp_i2c_info[] = { | ||
34 | { I2C_BOARD_INFO("ad7414", 0x4a) } | ||
35 | }; | ||
36 | |||
37 | static int __init warp_arch_init(void) | ||
38 | { | ||
39 | /* This should go away once support is moved to the dts. */ | ||
40 | i2c_register_board_info(0, warp_i2c_info, ARRAY_SIZE(warp_i2c_info)); | ||
41 | return 0; | ||
42 | } | ||
43 | machine_arch_initcall(warp, warp_arch_init); | ||
44 | |||
30 | static int __init warp_device_probe(void) | 45 | static int __init warp_device_probe(void) |
31 | { | 46 | { |
32 | of_platform_bus_probe(NULL, warp_of_bus, NULL); | 47 | of_platform_bus_probe(NULL, warp_of_bus, NULL); |
@@ -52,61 +67,232 @@ define_machine(warp) { | |||
52 | }; | 67 | }; |
53 | 68 | ||
54 | 69 | ||
55 | #define LED_GREEN (0x80000000 >> 0) | 70 | /* I am not sure this is the best place for this... */ |
56 | #define LED_RED (0x80000000 >> 1) | 71 | static int __init warp_post_info(void) |
72 | { | ||
73 | struct device_node *np; | ||
74 | void __iomem *fpga; | ||
75 | u32 post1, post2; | ||
76 | |||
77 | /* Sighhhh... POST information is in the sd area. */ | ||
78 | np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd"); | ||
79 | if (np == NULL) | ||
80 | return -ENOENT; | ||
81 | |||
82 | fpga = of_iomap(np, 0); | ||
83 | of_node_put(np); | ||
84 | if (fpga == NULL) | ||
85 | return -ENOENT; | ||
86 | |||
87 | post1 = in_be32(fpga + 0x40); | ||
88 | post2 = in_be32(fpga + 0x44); | ||
89 | |||
90 | iounmap(fpga); | ||
91 | |||
92 | if (post1 || post2) | ||
93 | printk(KERN_INFO "Warp POST %08x %08x\n", post1, post2); | ||
94 | else | ||
95 | printk(KERN_INFO "Warp POST OK\n"); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | machine_late_initcall(warp, warp_post_info); | ||
100 | |||
101 | |||
102 | #ifdef CONFIG_SENSORS_AD7414 | ||
103 | |||
104 | static LIST_HEAD(dtm_shutdown_list); | ||
105 | static void __iomem *dtm_fpga; | ||
106 | static void __iomem *gpio_base; | ||
107 | |||
108 | |||
109 | struct dtm_shutdown { | ||
110 | struct list_head list; | ||
111 | void (*func)(void *arg); | ||
112 | void *arg; | ||
113 | }; | ||
57 | 114 | ||
58 | 115 | ||
59 | /* This is for the power LEDs 1 = on, 0 = off, -1 = leave alone */ | 116 | int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) |
60 | void warp_set_power_leds(int green, int red) | ||
61 | { | 117 | { |
62 | static void __iomem *gpio_base = NULL; | 118 | struct dtm_shutdown *shutdown; |
63 | unsigned leds; | 119 | |
64 | 120 | shutdown = kmalloc(sizeof(struct dtm_shutdown), GFP_KERNEL); | |
65 | if (gpio_base == NULL) { | 121 | if (shutdown == NULL) |
66 | struct device_node *np; | 122 | return -ENOMEM; |
67 | 123 | ||
68 | /* Power LEDS are on the second GPIO controller */ | 124 | shutdown->func = func; |
69 | np = of_find_compatible_node(NULL, NULL, "ibm,gpio-440EP"); | 125 | shutdown->arg = arg; |
70 | if (np) | 126 | |
71 | np = of_find_compatible_node(np, NULL, "ibm,gpio-440EP"); | 127 | list_add(&shutdown->list, &dtm_shutdown_list); |
72 | if (np == NULL) { | 128 | |
73 | printk(KERN_ERR __FILE__ ": Unable to find gpio\n"); | 129 | return 0; |
74 | return; | 130 | } |
131 | |||
132 | int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg) | ||
133 | { | ||
134 | struct dtm_shutdown *shutdown; | ||
135 | |||
136 | list_for_each_entry(shutdown, &dtm_shutdown_list, list) | ||
137 | if (shutdown->func == func && shutdown->arg == arg) { | ||
138 | list_del(&shutdown->list); | ||
139 | kfree(shutdown); | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | static irqreturn_t temp_isr(int irq, void *context) | ||
147 | { | ||
148 | struct dtm_shutdown *shutdown; | ||
149 | |||
150 | local_irq_disable(); | ||
151 | |||
152 | /* Run through the shutdown list. */ | ||
153 | list_for_each_entry(shutdown, &dtm_shutdown_list, list) | ||
154 | shutdown->func(shutdown->arg); | ||
155 | |||
156 | printk(KERN_EMERG "\n\nCritical Temperature Shutdown\n"); | ||
157 | |||
158 | while (1) { | ||
159 | if (dtm_fpga) { | ||
160 | unsigned reset = in_be32(dtm_fpga + 0x14); | ||
161 | out_be32(dtm_fpga + 0x14, reset); | ||
75 | } | 162 | } |
76 | 163 | ||
77 | gpio_base = of_iomap(np, 0); | 164 | if (gpio_base) { |
78 | of_node_put(np); | 165 | unsigned leds = in_be32(gpio_base); |
79 | if (gpio_base == NULL) { | 166 | |
80 | printk(KERN_ERR __FILE__ ": Unable to map gpio"); | 167 | /* green off, red toggle */ |
81 | return; | 168 | leds &= ~0x80000000; |
169 | leds ^= 0x40000000; | ||
170 | |||
171 | out_be32(gpio_base, leds); | ||
82 | } | 172 | } |
173 | |||
174 | mdelay(500); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | static int pika_setup_leds(void) | ||
179 | { | ||
180 | struct device_node *np; | ||
181 | const u32 *gpios; | ||
182 | int len; | ||
183 | |||
184 | np = of_find_compatible_node(NULL, NULL, "linux,gpio-led"); | ||
185 | if (!np) { | ||
186 | printk(KERN_ERR __FILE__ ": Unable to find gpio-led\n"); | ||
187 | return -ENOENT; | ||
83 | } | 188 | } |
84 | 189 | ||
85 | leds = in_be32(gpio_base); | 190 | gpios = of_get_property(np, "gpios", &len); |
191 | of_node_put(np); | ||
192 | if (!gpios || len < 4) { | ||
193 | printk(KERN_ERR __FILE__ | ||
194 | ": Unable to get gpios property (%d)\n", len); | ||
195 | return -ENOENT; | ||
196 | } | ||
86 | 197 | ||
87 | switch (green) { | 198 | np = of_find_node_by_phandle(gpios[0]); |
88 | case 0: leds &= ~LED_GREEN; break; | 199 | if (!np) { |
89 | case 1: leds |= LED_GREEN; break; | 200 | printk(KERN_ERR __FILE__ ": Unable to find gpio\n"); |
201 | return -ENOENT; | ||
90 | } | 202 | } |
91 | switch (red) { | 203 | |
92 | case 0: leds &= ~LED_RED; break; | 204 | gpio_base = of_iomap(np, 0); |
93 | case 1: leds |= LED_RED; break; | 205 | of_node_put(np); |
206 | if (!gpio_base) { | ||
207 | printk(KERN_ERR __FILE__ ": Unable to map gpio"); | ||
208 | return -ENOMEM; | ||
94 | } | 209 | } |
95 | 210 | ||
96 | out_be32(gpio_base, leds); | 211 | return 0; |
97 | } | 212 | } |
98 | EXPORT_SYMBOL(warp_set_power_leds); | ||
99 | 213 | ||
214 | static void pika_setup_critical_temp(struct i2c_client *client) | ||
215 | { | ||
216 | struct device_node *np; | ||
217 | int irq, rc; | ||
218 | |||
219 | /* Do this before enabling critical temp interrupt since we | ||
220 | * may immediately interrupt. | ||
221 | */ | ||
222 | pika_setup_leds(); | ||
223 | |||
224 | /* These registers are in 1 degree increments. */ | ||
225 | i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */ | ||
226 | i2c_smbus_write_byte_data(client, 3, 55); /* Tlow */ | ||
227 | |||
228 | np = of_find_compatible_node(NULL, NULL, "adi,ad7414"); | ||
229 | if (np == NULL) { | ||
230 | printk(KERN_ERR __FILE__ ": Unable to find ad7414\n"); | ||
231 | return; | ||
232 | } | ||
233 | |||
234 | irq = irq_of_parse_and_map(np, 0); | ||
235 | of_node_put(np); | ||
236 | if (irq == NO_IRQ) { | ||
237 | printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n"); | ||
238 | return; | ||
239 | } | ||
240 | |||
241 | rc = request_irq(irq, temp_isr, 0, "ad7414", NULL); | ||
242 | if (rc) { | ||
243 | printk(KERN_ERR __FILE__ | ||
244 | ": Unable to request ad7414 irq %d = %d\n", irq, rc); | ||
245 | return; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static inline void pika_dtm_check_fan(void __iomem *fpga) | ||
250 | { | ||
251 | static int fan_state; | ||
252 | u32 fan = in_be32(fpga + 0x34) & (1 << 14); | ||
253 | |||
254 | if (fan_state != fan) { | ||
255 | fan_state = fan; | ||
256 | if (fan) | ||
257 | printk(KERN_WARNING "Fan rotation error detected." | ||
258 | " Please check hardware.\n"); | ||
259 | } | ||
260 | } | ||
100 | 261 | ||
101 | #ifdef CONFIG_SENSORS_AD7414 | ||
102 | static int pika_dtm_thread(void __iomem *fpga) | 262 | static int pika_dtm_thread(void __iomem *fpga) |
103 | { | 263 | { |
104 | extern int ad7414_get_temp(int index); | 264 | struct i2c_adapter *adap; |
265 | struct i2c_client *client; | ||
266 | |||
267 | /* We loop in case either driver was compiled as a module and | ||
268 | * has not been insmoded yet. | ||
269 | */ | ||
270 | while (!(adap = i2c_get_adapter(0))) { | ||
271 | set_current_state(TASK_INTERRUPTIBLE); | ||
272 | schedule_timeout(HZ); | ||
273 | } | ||
274 | |||
275 | while (1) { | ||
276 | list_for_each_entry(client, &adap->clients, list) | ||
277 | if (client->addr == 0x4a) | ||
278 | goto found_it; | ||
279 | |||
280 | set_current_state(TASK_INTERRUPTIBLE); | ||
281 | schedule_timeout(HZ); | ||
282 | } | ||
283 | |||
284 | found_it: | ||
285 | i2c_put_adapter(adap); | ||
286 | |||
287 | pika_setup_critical_temp(client); | ||
288 | |||
289 | printk(KERN_INFO "PIKA DTM thread running.\n"); | ||
105 | 290 | ||
106 | while (!kthread_should_stop()) { | 291 | while (!kthread_should_stop()) { |
107 | int temp = ad7414_get_temp(0); | 292 | u16 temp = swab16(i2c_smbus_read_word_data(client, 0)); |
293 | out_be32(fpga + 0x20, temp); | ||
108 | 294 | ||
109 | out_be32(fpga, temp); | 295 | pika_dtm_check_fan(fpga); |
110 | 296 | ||
111 | set_current_state(TASK_INTERRUPTIBLE); | 297 | set_current_state(TASK_INTERRUPTIBLE); |
112 | schedule_timeout(HZ); | 298 | schedule_timeout(HZ); |
@@ -115,37 +301,44 @@ static int pika_dtm_thread(void __iomem *fpga) | |||
115 | return 0; | 301 | return 0; |
116 | } | 302 | } |
117 | 303 | ||
304 | |||
118 | static int __init pika_dtm_start(void) | 305 | static int __init pika_dtm_start(void) |
119 | { | 306 | { |
120 | struct task_struct *dtm_thread; | 307 | struct task_struct *dtm_thread; |
121 | struct device_node *np; | 308 | struct device_node *np; |
122 | struct resource res; | ||
123 | void __iomem *fpga; | ||
124 | 309 | ||
125 | np = of_find_compatible_node(NULL, NULL, "pika,fpga"); | 310 | np = of_find_compatible_node(NULL, NULL, "pika,fpga"); |
126 | if (np == NULL) | 311 | if (np == NULL) |
127 | return -ENOENT; | 312 | return -ENOENT; |
128 | 313 | ||
129 | /* We do not call of_iomap here since it would map in the entire | 314 | dtm_fpga = of_iomap(np, 0); |
130 | * fpga space, which is over 8k. | ||
131 | */ | ||
132 | if (of_address_to_resource(np, 0, &res)) { | ||
133 | of_node_put(np); | ||
134 | return -ENOENT; | ||
135 | } | ||
136 | of_node_put(np); | 315 | of_node_put(np); |
137 | 316 | if (dtm_fpga == NULL) | |
138 | fpga = ioremap(res.start, 0x24); | ||
139 | if (fpga == NULL) | ||
140 | return -ENOENT; | 317 | return -ENOENT; |
141 | 318 | ||
142 | dtm_thread = kthread_run(pika_dtm_thread, fpga + 0x20, "pika-dtm"); | 319 | dtm_thread = kthread_run(pika_dtm_thread, dtm_fpga, "pika-dtm"); |
143 | if (IS_ERR(dtm_thread)) { | 320 | if (IS_ERR(dtm_thread)) { |
144 | iounmap(fpga); | 321 | iounmap(dtm_fpga); |
145 | return PTR_ERR(dtm_thread); | 322 | return PTR_ERR(dtm_thread); |
146 | } | 323 | } |
147 | 324 | ||
148 | return 0; | 325 | return 0; |
149 | } | 326 | } |
150 | device_initcall(pika_dtm_start); | 327 | machine_late_initcall(warp, pika_dtm_start); |
328 | |||
329 | #else /* !CONFIG_SENSORS_AD7414 */ | ||
330 | |||
331 | int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) | ||
332 | { | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg) | ||
337 | { | ||
338 | return 0; | ||
339 | } | ||
340 | |||
151 | #endif | 341 | #endif |
342 | |||
343 | EXPORT_SYMBOL(pika_dtm_register_shutdown); | ||
344 | EXPORT_SYMBOL(pika_dtm_unregister_shutdown); | ||