blob: 879783a41cfd8dd4067e246ea3150f6eb9066511 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * arch/ppc/syslib/ppc_sys.c
3 *
4 * PPC System library functions
5 *
Kumar Gala4c8d3d92005-11-13 16:06:30 -08006 * Maintainer: Kumar Gala <galak@kernel.crashing.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * Copyright 2005 Freescale Semiconductor Inc.
Kumar Gala88adfe72005-09-03 15:55:46 -07009 * Copyright 2005 MontaVista, Inc. by Vitaly Bordug <vbordug@ru.mvista.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16
Tim Schmielau8c65b4a2005-11-07 00:59:43 -080017#include <linux/string.h>
Vitaly Bordug75288c72006-01-20 22:22:34 +030018#include <linux/bootmem.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <asm/ppc_sys.h>
20
21int (*ppc_sys_device_fixup) (struct platform_device * pdev);
22
23static int ppc_sys_inited;
Vitaly Bordug75288c72006-01-20 22:22:34 +030024static int ppc_sys_func_inited;
25
26static const char *ppc_sys_func_names[] = {
27 [PPC_SYS_FUNC_DUMMY] = "dummy",
28 [PPC_SYS_FUNC_ETH] = "eth",
29 [PPC_SYS_FUNC_UART] = "uart",
30 [PPC_SYS_FUNC_HLDC] = "hldc",
31 [PPC_SYS_FUNC_USB] = "usb",
32 [PPC_SYS_FUNC_IRDA] = "irda",
33};
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35void __init identify_ppc_sys_by_id(u32 id)
36{
37 unsigned int i = 0;
38 while (1) {
39 if ((ppc_sys_specs[i].mask & id) == ppc_sys_specs[i].value)
40 break;
41 i++;
42 }
43
44 cur_ppc_sys_spec = &ppc_sys_specs[i];
45
46 return;
47}
48
49void __init identify_ppc_sys_by_name(char *name)
50{
Kumar Gala88adfe72005-09-03 15:55:46 -070051 unsigned int i = 0;
Vitaly Bordug75288c72006-01-20 22:22:34 +030052 while (ppc_sys_specs[i].ppc_sys_name[0]) {
Kumar Gala88adfe72005-09-03 15:55:46 -070053 if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
54 break;
55 i++;
56 }
57 cur_ppc_sys_spec = &ppc_sys_specs[i];
Vitaly Bordug75288c72006-01-20 22:22:34 +030058
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 return;
60}
61
Kumar Gala88adfe72005-09-03 15:55:46 -070062static int __init count_sys_specs(void)
63{
64 int i = 0;
65 while (ppc_sys_specs[i].ppc_sys_name[0])
66 i++;
67 return i;
68}
69
70static int __init find_chip_by_name_and_id(char *name, u32 id)
71{
72 int ret = -1;
73 unsigned int i = 0;
74 unsigned int j = 0;
75 unsigned int dups = 0;
76
77 unsigned char matched[count_sys_specs()];
78
79 while (ppc_sys_specs[i].ppc_sys_name[0]) {
80 if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name))
81 matched[j++] = i;
82 i++;
83 }
Vitaly Bordug1461b4e2005-10-28 17:46:28 -070084
85 ret = i;
86
Kumar Gala88adfe72005-09-03 15:55:46 -070087 if (j != 0) {
88 for (i = 0; i < j; i++) {
89 if ((ppc_sys_specs[matched[i]].mask & id) ==
90 ppc_sys_specs[matched[i]].value) {
91 ret = matched[i];
92 dups++;
93 }
94 }
95 ret = (dups == 1) ? ret : (-1 * dups);
96 }
97 return ret;
98}
99
100void __init identify_ppc_sys_by_name_and_id(char *name, u32 id)
101{
102 int i = find_chip_by_name_and_id(name, id);
103 BUG_ON(i < 0);
104 cur_ppc_sys_spec = &ppc_sys_specs[i];
105}
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107/* Update all memory resources by paddr, call before platform_device_register */
108void __init
109ppc_sys_fixup_mem_resource(struct platform_device *pdev, phys_addr_t paddr)
110{
111 int i;
112 for (i = 0; i < pdev->num_resources; i++) {
113 struct resource *r = &pdev->resource[i];
114 if ((r->flags & IORESOURCE_MEM) == IORESOURCE_MEM) {
115 r->start += paddr;
116 r->end += paddr;
117 }
118 }
119}
120
121/* Get platform_data pointer out of platform device, call before platform_device_register */
122void *__init ppc_sys_get_pdata(enum ppc_sys_devices dev)
123{
124 return ppc_sys_platform_devices[dev].dev.platform_data;
125}
126
127void ppc_sys_device_remove(enum ppc_sys_devices dev)
128{
129 unsigned int i;
130
131 if (ppc_sys_inited) {
132 platform_device_unregister(&ppc_sys_platform_devices[dev]);
133 } else {
134 if (cur_ppc_sys_spec == NULL)
135 return;
136 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++)
137 if (cur_ppc_sys_spec->device_list[i] == dev)
138 cur_ppc_sys_spec->device_list[i] = -1;
139 }
140}
141
Vitaly Bordug75288c72006-01-20 22:22:34 +0300142/* Platform-notify mapping
143 * Helper function for BSP code to assign board-specific platfom-divice bits
144 */
145
146void platform_notify_map(const struct platform_notify_dev_map *map,
147 struct device *dev)
148{
149 struct platform_device *pdev;
150 int len, idx;
151 const char *s;
152
153 /* do nothing if no device or no bus_id */
154 if (!dev || !dev->bus_id)
155 return;
156
157 /* call per device map */
158 while (map->bus_id != NULL) {
159 idx = -1;
160 s = strrchr(dev->bus_id, '.');
161 if (s != NULL)
162 idx = (int)simple_strtol(s + 1, NULL, 10);
163 else
164 s = dev->bus_id;
165
166 len = s - dev->bus_id;
167
168 if (!strncmp(dev->bus_id, map->bus_id, len)) {
169 pdev = container_of(dev, struct platform_device, dev);
170 map->rtn(pdev, idx);
171 }
172 map++;
173 }
174}
175
176/*
177 Function assignment stuff.
178 Intended to work as follows:
179 the device name defined in foo_devices.c will be concatenated with :"func",
180 where func is string map of respective function from platfom_device_func enum
181
182 The PPC_SYS_FUNC_DUMMY function is intended to remove all assignments, making the device to appear
183 in platform bus with unmodified name.
184 */
185
186/*
187 Here we'll replace .name pointers with fixed-lenght strings
188 Hereby, this should be called *before* any func stuff triggeded.
189 */
190void ppc_sys_device_initfunc(void)
191{
192 int i;
193 const char *name;
194 static char new_names[NUM_PPC_SYS_DEVS][BUS_ID_SIZE];
195 enum ppc_sys_devices cur_dev;
196
197 /* If inited yet, do nothing */
198 if (ppc_sys_func_inited)
199 return;
200
201 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
202 if ((cur_dev = cur_ppc_sys_spec->device_list[i]) < 0)
203 continue;
204
205 if (ppc_sys_platform_devices[cur_dev].name) {
206 /*backup name */
207 name = ppc_sys_platform_devices[cur_dev].name;
208 strlcpy(new_names[i], name, BUS_ID_SIZE);
209 ppc_sys_platform_devices[cur_dev].name = new_names[i];
210 }
211 }
212
213 ppc_sys_func_inited = 1;
214}
215
216/*The "engine" of the func stuff. Here we either concat specified function string description
217 to the name, or remove it if PPC_SYS_FUNC_DUMMY parameter is passed here*/
218void ppc_sys_device_setfunc(enum ppc_sys_devices dev,
219 enum platform_device_func func)
220{
221 char *s;
222 char *name = (char *)ppc_sys_platform_devices[dev].name;
223 char tmp[BUS_ID_SIZE];
224
225 if (!ppc_sys_func_inited) {
226 printk(KERN_ERR "Unable to alter function - not inited!\n");
227 return;
228 }
229
230 if (ppc_sys_inited) {
231 platform_device_unregister(&ppc_sys_platform_devices[dev]);
232 }
233
234 if ((s = (char *)strchr(name, ':')) != NULL) { /* reassign */
235 /* Either change the name after ':' or remove func modifications */
236 if (func != PPC_SYS_FUNC_DUMMY)
237 strlcpy(s + 1, ppc_sys_func_names[func], BUS_ID_SIZE);
238 else
239 *s = 0;
240 } else if (func != PPC_SYS_FUNC_DUMMY) {
241 /* do assignment if it is not just "clear" request */
242 sprintf(tmp, "%s:%s", name, ppc_sys_func_names[func]);
243 strlcpy(name, tmp, BUS_ID_SIZE);
244 }
245
246 if (ppc_sys_inited) {
247 platform_device_register(&ppc_sys_platform_devices[dev]);
248 }
249}
250
251void ppc_sys_device_disable(enum ppc_sys_devices dev)
252{
253 BUG_ON(cur_ppc_sys_spec == NULL);
254
255 /*Check if it is enabled*/
256 if(!(cur_ppc_sys_spec->config[dev] & PPC_SYS_CONFIG_DISABLED)) {
257 if (ppc_sys_inited) {
258 platform_device_unregister(&ppc_sys_platform_devices[dev]);
259 }
260 cur_ppc_sys_spec->config[dev] |= PPC_SYS_CONFIG_DISABLED;
261 }
262}
263
264void ppc_sys_device_enable(enum ppc_sys_devices dev)
265{
266 BUG_ON(cur_ppc_sys_spec == NULL);
267
268 /*Check if it is disabled*/
269 if(cur_ppc_sys_spec->config[dev] & PPC_SYS_CONFIG_DISABLED) {
270 if (ppc_sys_inited) {
271 platform_device_register(&ppc_sys_platform_devices[dev]);
272 }
273 cur_ppc_sys_spec->config[dev] &= ~PPC_SYS_CONFIG_DISABLED;
274 }
275
276}
277
278void ppc_sys_device_enable_all(void)
279{
280 enum ppc_sys_devices cur_dev;
281 int i;
282
283 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
284 cur_dev = cur_ppc_sys_spec->device_list[i];
285 ppc_sys_device_enable(cur_dev);
286 }
287}
288
289void ppc_sys_device_disable_all(void)
290{
291 enum ppc_sys_devices cur_dev;
292 int i;
293
294 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
295 cur_dev = cur_ppc_sys_spec->device_list[i];
296 ppc_sys_device_disable(cur_dev);
297 }
298}
299
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301static int __init ppc_sys_init(void)
302{
303 unsigned int i, dev_id, ret = 0;
304
305 BUG_ON(cur_ppc_sys_spec == NULL);
306
307 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
308 dev_id = cur_ppc_sys_spec->device_list[i];
Vitaly Bordug75288c72006-01-20 22:22:34 +0300309 if ((dev_id != -1) &&
310 !(cur_ppc_sys_spec->config[dev_id] & PPC_SYS_CONFIG_DISABLED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 if (ppc_sys_device_fixup != NULL)
312 ppc_sys_device_fixup(&ppc_sys_platform_devices
313 [dev_id]);
314 if (platform_device_register
315 (&ppc_sys_platform_devices[dev_id])) {
316 ret = 1;
317 printk(KERN_ERR
318 "unable to register device %d\n",
319 dev_id);
320 }
321 }
322 }
323
324 ppc_sys_inited = 1;
325 return ret;
326}
327
328subsys_initcall(ppc_sys_init);