aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Dooks <ben@fluff.org.uk>2007-02-20 16:58:01 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-20 20:10:14 -0500
commitb6d6454fdb66f3829af8b92ab06825b6060fdf7e (patch)
tree8de7c81e0c56fef5bc70870d107d346ca7a83529
parent60e114d1134555d1813e20a8cd86304331da05c7 (diff)
[PATCH] mfd: SM501 core driver
This driver provides the core functionality of the SM501, which is a multi-function chip including two framebuffers, video acceleration, USB, and many other peripheral blocks. The driver exports a number of entries for the peripheral drivers to use. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Vincent Sanders <vince@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/mfd/Kconfig14
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/sm501.c1148
-rw-r--r--include/linux/sm501-regs.h357
-rw-r--r--include/linux/sm501.h170
5 files changed, 1691 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fc3c8854f430..ab6e985275b2 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2,6 +2,20 @@
2# Multifunction miscellaneous devices 2# Multifunction miscellaneous devices
3# 3#
4 4
5menu "Multifunction device drivers"
6
7config MFD_SM501
8 tristate "Support for Silicon Motion SM501"
9 ---help---
10 This is the core driver for the Silicon Motion SM501 multimedia
11 companion chip. This device is a multifunction device which may
12 provide numerous interfaces including USB host controller USB gadget,
13 Asyncronous Serial ports, Audio functions and a dual display video
14 interface. The device may be connected by PCI or local bus with
15 varying functions enabled.
16
17endmenu
18
5menu "Multimedia Capabilities Port drivers" 19menu "Multimedia Capabilities Port drivers"
6 depends on ARCH_SA1100 20 depends on ARCH_SA1100
7 21
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index adb29b5368a8..51432091b323 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -2,6 +2,8 @@
2# Makefile for multifunction miscellaneous devices 2# Makefile for multifunction miscellaneous devices
3# 3#
4 4
5obj-$(CONFIG_MFD_SM501) += sm501.o
6
5obj-$(CONFIG_MCP) += mcp-core.o 7obj-$(CONFIG_MCP) += mcp-core.o
6obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o 8obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
7obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o 9obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
new file mode 100644
index 000000000000..5c5a1e2dda8a
--- /dev/null
+++ b/drivers/mfd/sm501.c
@@ -0,0 +1,1148 @@
1/* linux/drivers/mfd/sm501.c
2 *
3 * Copyright (C) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * Vincent Sanders <vince@simtec.co.uk>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * SM501 MFD driver
12*/
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/delay.h>
17#include <linux/init.h>
18#include <linux/list.h>
19#include <linux/device.h>
20#include <linux/platform_device.h>
21#include <linux/pci.h>
22
23#include <linux/sm501.h>
24#include <linux/sm501-regs.h>
25
26#include <asm/io.h>
27
28struct sm501_device {
29 struct list_head list;
30 struct platform_device pdev;
31};
32
33struct sm501_devdata {
34 spinlock_t reg_lock;
35 struct mutex clock_lock;
36 struct list_head devices;
37
38 struct device *dev;
39 struct resource *io_res;
40 struct resource *mem_res;
41 struct resource *regs_claim;
42 struct sm501_platdata *platdata;
43
44 int unit_power[20];
45 unsigned int pdev_id;
46 unsigned int irq;
47 void __iomem *regs;
48};
49
50#define MHZ (1000 * 1000)
51
52#ifdef DEBUG
53static const unsigned int misc_div[] = {
54 [0] = 1,
55 [1] = 2,
56 [2] = 4,
57 [3] = 8,
58 [4] = 16,
59 [5] = 32,
60 [6] = 64,
61 [7] = 128,
62 [8] = 3,
63 [9] = 6,
64 [10] = 12,
65 [11] = 24,
66 [12] = 48,
67 [13] = 96,
68 [14] = 192,
69 [15] = 384,
70};
71
72static const unsigned int px_div[] = {
73 [0] = 1,
74 [1] = 2,
75 [2] = 4,
76 [3] = 8,
77 [4] = 16,
78 [5] = 32,
79 [6] = 64,
80 [7] = 128,
81 [8] = 3,
82 [9] = 6,
83 [10] = 12,
84 [11] = 24,
85 [12] = 48,
86 [13] = 96,
87 [14] = 192,
88 [15] = 384,
89 [16] = 5,
90 [17] = 10,
91 [18] = 20,
92 [19] = 40,
93 [20] = 80,
94 [21] = 160,
95 [22] = 320,
96 [23] = 604,
97};
98
99static unsigned long decode_div(unsigned long pll2, unsigned long val,
100 unsigned int lshft, unsigned int selbit,
101 unsigned long mask, const unsigned int *dtab)
102{
103 if (val & selbit)
104 pll2 = 288 * MHZ;
105
106 return pll2 / dtab[(val >> lshft) & mask];
107}
108
109#define fmt_freq(x) ((x) / MHZ), ((x) % MHZ), (x)
110
111/* sm501_dump_clk
112 *
113 * Print out the current clock configuration for the device
114*/
115
116static void sm501_dump_clk(struct sm501_devdata *sm)
117{
118 unsigned long misct = readl(sm->regs + SM501_MISC_TIMING);
119 unsigned long pm0 = readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
120 unsigned long pm1 = readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
121 unsigned long pmc = readl(sm->regs + SM501_POWER_MODE_CONTROL);
122 unsigned long sdclk0, sdclk1;
123 unsigned long pll2 = 0;
124
125 switch (misct & 0x30) {
126 case 0x00:
127 pll2 = 336 * MHZ;
128 break;
129 case 0x10:
130 pll2 = 288 * MHZ;
131 break;
132 case 0x20:
133 pll2 = 240 * MHZ;
134 break;
135 case 0x30:
136 pll2 = 192 * MHZ;
137 break;
138 }
139
140 sdclk0 = (misct & (1<<12)) ? pll2 : 288 * MHZ;
141 sdclk0 /= misc_div[((misct >> 8) & 0xf)];
142
143 sdclk1 = (misct & (1<<20)) ? pll2 : 288 * MHZ;
144 sdclk1 /= misc_div[((misct >> 16) & 0xf)];
145
146 dev_dbg(sm->dev, "MISCT=%08lx, PM0=%08lx, PM1=%08lx\n",
147 misct, pm0, pm1);
148
149 dev_dbg(sm->dev, "PLL2 = %ld.%ld MHz (%ld), SDCLK0=%08lx, SDCLK1=%08lx\n",
150 fmt_freq(pll2), sdclk0, sdclk1);
151
152 dev_dbg(sm->dev, "SDRAM: PM0=%ld, PM1=%ld\n", sdclk0, sdclk1);
153
154 dev_dbg(sm->dev, "PM0[%c]: "
155 "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
156x "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
157 (pmc & 3 ) == 0 ? '*' : '-',
158 fmt_freq(decode_div(pll2, pm0, 24, 1<<29, 31, px_div)),
159 fmt_freq(decode_div(pll2, pm0, 16, 1<<20, 15, misc_div)),
160 fmt_freq(decode_div(pll2, pm0, 8, 1<<12, 15, misc_div)),
161 fmt_freq(decode_div(pll2, pm0, 0, 1<<4, 15, misc_div)));
162
163 dev_dbg(sm->dev, "PM1[%c]: "
164 "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
165 "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
166 (pmc & 3 ) == 1 ? '*' : '-',
167 fmt_freq(decode_div(pll2, pm1, 24, 1<<29, 31, px_div)),
168 fmt_freq(decode_div(pll2, pm1, 16, 1<<20, 15, misc_div)),
169 fmt_freq(decode_div(pll2, pm1, 8, 1<<12, 15, misc_div)),
170 fmt_freq(decode_div(pll2, pm1, 0, 1<<4, 15, misc_div)));
171}
172#else
173static void sm501_dump_clk(struct sm501_devdata *sm)
174{
175}
176#endif
177
178/* sm501_sync_regs
179 *
180 * ensure the
181*/
182
183static void sm501_sync_regs(struct sm501_devdata *sm)
184{
185 readl(sm->regs);
186}
187
188/* sm501_misc_control
189 *
190 * alters the misceleneous control parameters
191*/
192
193int sm501_misc_control(struct device *dev,
194 unsigned long set, unsigned long clear)
195{
196 struct sm501_devdata *sm = dev_get_drvdata(dev);
197 unsigned long misc;
198 unsigned long save;
199 unsigned long to;
200
201 spin_lock_irqsave(&sm->reg_lock, save);
202
203 misc = readl(sm->regs + SM501_MISC_CONTROL);
204 to = (misc & ~clear) | set;
205
206 if (to != misc) {
207 writel(to, sm->regs + SM501_MISC_CONTROL);
208 sm501_sync_regs(sm);
209
210 dev_dbg(sm->dev, "MISC_CONTROL %08lx\n", misc);
211 }
212
213 spin_unlock_irqrestore(&sm->reg_lock, save);
214 return to;
215}
216
217EXPORT_SYMBOL_GPL(sm501_misc_control);
218
219/* sm501_modify_reg
220 *
221 * Modify a register in the SM501 which may be shared with other
222 * drivers.
223*/
224
225unsigned long sm501_modify_reg(struct device *dev,
226 unsigned long reg,
227 unsigned long set,
228 unsigned long clear)
229{
230 struct sm501_devdata *sm = dev_get_drvdata(dev);
231 unsigned long data;
232 unsigned long save;
233
234 spin_lock_irqsave(&sm->reg_lock, save);
235
236 data = readl(sm->regs + reg);
237 data |= set;
238 data &= ~clear;
239
240 writel(data, sm->regs + reg);
241 sm501_sync_regs(sm);
242
243 spin_unlock_irqrestore(&sm->reg_lock, save);
244
245 return data;
246}
247
248EXPORT_SYMBOL_GPL(sm501_modify_reg);
249
250unsigned long sm501_gpio_get(struct device *dev,
251 unsigned long gpio)
252{
253 struct sm501_devdata *sm = dev_get_drvdata(dev);
254 unsigned long result;
255 unsigned long reg;
256
257 reg = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW;
258 result = readl(sm->regs + reg);
259
260 result >>= (gpio & 31);
261 return result & 1UL;
262}
263
264EXPORT_SYMBOL_GPL(sm501_gpio_get);
265
266void sm501_gpio_set(struct device *dev,
267 unsigned long gpio,
268 unsigned int to,
269 unsigned int dir)
270{
271 struct sm501_devdata *sm = dev_get_drvdata(dev);
272
273 unsigned long bit = 1 << (gpio & 31);
274 unsigned long base;
275 unsigned long save;
276 unsigned long val;
277
278 base = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW;
279 base += SM501_GPIO;
280
281 spin_lock_irqsave(&sm->reg_lock, save);
282
283 val = readl(sm->regs + base) & ~bit;
284 if (to)
285 val |= bit;
286 writel(val, sm->regs + base);
287
288 val = readl(sm->regs + SM501_GPIO_DDR_LOW) & ~bit;
289 if (dir)
290 val |= bit;
291
292 writel(val, sm->regs + SM501_GPIO_DDR_LOW);
293 sm501_sync_regs(sm);
294
295 spin_unlock_irqrestore(&sm->reg_lock, save);
296
297}
298
299EXPORT_SYMBOL_GPL(sm501_gpio_set);
300
301
302/* sm501_unit_power
303 *
304 * alters the power active gate to set specific units on or off
305 */
306
307int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
308{
309 struct sm501_devdata *sm = dev_get_drvdata(dev);
310 unsigned long mode;
311 unsigned long gate;
312 unsigned long clock;
313
314 mutex_lock(&sm->clock_lock);
315
316 mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
317 gate = readl(sm->regs + SM501_CURRENT_GATE);
318 clock = readl(sm->regs + SM501_CURRENT_CLOCK);
319
320 mode &= 3; /* get current power mode */
321
322 if (unit > ARRAY_SIZE(sm->unit_power)) {
323 dev_err(dev, "%s: bad unit %d\n", __FUNCTION__, unit);
324 goto already;
325 }
326
327 dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __FUNCTION__, unit,
328 sm->unit_power[unit], to);
329
330 if (to == 0 && sm->unit_power[unit] == 0) {
331 dev_err(sm->dev, "unit %d is already shutdown\n", unit);
332 goto already;
333 }
334
335 sm->unit_power[unit] += to ? 1 : -1;
336 to = sm->unit_power[unit] ? 1 : 0;
337
338 if (to) {
339 if (gate & (1 << unit))
340 goto already;
341 gate |= (1 << unit);
342 } else {
343 if (!(gate & (1 << unit)))
344 goto already;
345 gate &= ~(1 << unit);
346 }
347
348 switch (mode) {
349 case 1:
350 writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
351 writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
352 mode = 0;
353 break;
354 case 2:
355 case 0:
356 writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
357 writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
358 mode = 1;
359 break;
360
361 default:
362 return -1;
363 }
364
365 writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
366 sm501_sync_regs(sm);
367
368 dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
369 gate, clock, mode);
370
371 msleep(16);
372
373 already:
374 mutex_unlock(&sm->clock_lock);
375 return gate;
376}
377
378EXPORT_SYMBOL_GPL(sm501_unit_power);
379
380
381/* Perform a rounded division. */
382static long sm501fb_round_div(long num, long denom)
383{
384 /* n / d + 1 / 2 = (2n + d) / 2d */
385 return (2 * num + denom) / (2 * denom);
386}
387
388/* clock value structure. */
389struct sm501_clock {
390 unsigned long mclk;
391 int divider;
392 int shift;
393};
394
395/* sm501_select_clock
396 *
397 * selects nearest discrete clock frequency the SM501 can achive
398 * the maximum divisor is 3 or 5
399 */
400static unsigned long sm501_select_clock(unsigned long freq,
401 struct sm501_clock *clock,
402 int max_div)
403{
404 unsigned long mclk;
405 int divider;
406 int shift;
407 long diff;
408 long best_diff = 999999999;
409
410 /* Try 288MHz and 336MHz clocks. */
411 for (mclk = 288000000; mclk <= 336000000; mclk += 48000000) {
412 /* try dividers 1 and 3 for CRT and for panel,
413 try divider 5 for panel only.*/
414
415 for (divider = 1; divider <= max_div; divider += 2) {
416 /* try all 8 shift values.*/
417 for (shift = 0; shift < 8; shift++) {
418 /* Calculate difference to requested clock */
419 diff = sm501fb_round_div(mclk, divider << shift) - freq;
420 if (diff < 0)
421 diff = -diff;
422
423 /* If it is less than the current, use it */
424 if (diff < best_diff) {
425 best_diff = diff;
426
427 clock->mclk = mclk;
428 clock->divider = divider;
429 clock->shift = shift;
430 }
431 }
432 }
433 }
434
435 /* Return best clock. */
436 return clock->mclk / (clock->divider << clock->shift);
437}
438
439/* sm501_set_clock
440 *
441 * set one of the four clock sources to the closest available frequency to
442 * the one specified
443*/
444
445unsigned long sm501_set_clock(struct device *dev,
446 int clksrc,
447 unsigned long req_freq)
448{
449 struct sm501_devdata *sm = dev_get_drvdata(dev);
450 unsigned long mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
451 unsigned long gate = readl(sm->regs + SM501_CURRENT_GATE);
452 unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK);
453 unsigned char reg;
454 unsigned long sm501_freq; /* the actual frequency acheived */
455
456 struct sm501_clock to;
457
458 /* find achivable discrete frequency and setup register value
459 * accordingly, V2XCLK, MCLK and M1XCLK are the same P2XCLK
460 * has an extra bit for the divider */
461
462 switch (clksrc) {
463 case SM501_CLOCK_P2XCLK:
464 /* This clock is divided in half so to achive the
465 * requested frequency the value must be multiplied by
466 * 2. This clock also has an additional pre divisor */
467
468 sm501_freq = (sm501_select_clock(2 * req_freq, &to, 5) / 2);
469 reg=to.shift & 0x07;/* bottom 3 bits are shift */
470 if (to.divider == 3)
471 reg |= 0x08; /* /3 divider required */
472 else if (to.divider == 5)
473 reg |= 0x10; /* /5 divider required */
474 if (to.mclk != 288000000)
475 reg |= 0x20; /* which mclk pll is source */
476 break;
477
478 case SM501_CLOCK_V2XCLK:
479 /* This clock is divided in half so to achive the
480 * requested frequency the value must be multiplied by 2. */
481
482 sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
483 reg=to.shift & 0x07; /* bottom 3 bits are shift */
484 if (to.divider == 3)
485 reg |= 0x08; /* /3 divider required */
486 if (to.mclk != 288000000)
487 reg |= 0x10; /* which mclk pll is source */
488 break;
489
490 case SM501_CLOCK_MCLK:
491 case SM501_CLOCK_M1XCLK:
492 /* These clocks are the same and not further divided */
493
494 sm501_freq = sm501_select_clock( req_freq, &to, 3);
495 reg=to.shift & 0x07; /* bottom 3 bits are shift */
496 if (to.divider == 3)
497 reg |= 0x08; /* /3 divider required */
498 if (to.mclk != 288000000)
499 reg |= 0x10; /* which mclk pll is source */
500 break;
501
502 default:
503 return 0; /* this is bad */
504 }
505
506 mutex_lock(&sm->clock_lock);
507
508 mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
509 gate = readl(sm->regs + SM501_CURRENT_GATE);
510 clock = readl(sm->regs + SM501_CURRENT_CLOCK);
511
512 clock = clock & ~(0xFF << clksrc);
513 clock |= reg<<clksrc;
514
515 mode &= 3; /* find current mode */
516
517 switch (mode) {
518 case 1:
519 writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
520 writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
521 mode = 0;
522 break;
523 case 2:
524 case 0:
525 writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
526 writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
527 mode = 1;
528 break;
529
530 default:
531 mutex_unlock(&sm->clock_lock);
532 return -1;
533 }
534
535 writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
536 sm501_sync_regs(sm);
537
538 dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
539 gate, clock, mode);
540
541 msleep(16);
542 mutex_unlock(&sm->clock_lock);
543
544 sm501_dump_clk(sm);
545
546 return sm501_freq;
547}
548
549EXPORT_SYMBOL_GPL(sm501_set_clock);
550
551/* sm501_find_clock
552 *
553 * finds the closest available frequency for a given clock
554*/
555
556unsigned long sm501_find_clock(int clksrc,
557 unsigned long req_freq)
558{
559 unsigned long sm501_freq; /* the frequency achiveable by the 501 */
560 struct sm501_clock to;
561
562 switch (clksrc) {
563 case SM501_CLOCK_P2XCLK:
564 sm501_freq = (sm501_select_clock(2 * req_freq, &to, 5) / 2);
565 break;
566
567 case SM501_CLOCK_V2XCLK:
568 sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
569 break;
570
571 case SM501_CLOCK_MCLK:
572 case SM501_CLOCK_M1XCLK:
573 sm501_freq = sm501_select_clock(req_freq, &to, 3);
574 break;
575
576 default:
577 sm501_freq = 0; /* error */
578 }
579
580 return sm501_freq;
581}
582
583EXPORT_SYMBOL_GPL(sm501_find_clock);
584
585static struct sm501_device *to_sm_device(struct platform_device *pdev)
586{
587 return container_of(pdev, struct sm501_device, pdev);
588}
589
590/* sm501_device_release
591 *
592 * A release function for the platform devices we create to allow us to
593 * free any items we allocated
594*/
595
596static void sm501_device_release(struct device *dev)
597{
598 kfree(to_sm_device(to_platform_device(dev)));
599}
600
601/* sm501_create_subdev
602 *
603 * Create a skeleton platform device with resources for passing to a
604 * sub-driver
605*/
606
607static struct platform_device *
608sm501_create_subdev(struct sm501_devdata *sm,
609 char *name, unsigned int res_count)
610{
611 struct sm501_device *smdev;
612
613 smdev = kzalloc(sizeof(struct sm501_device) +
614 sizeof(struct resource) * res_count, GFP_KERNEL);
615 if (!smdev)
616 return NULL;
617
618 smdev->pdev.dev.release = sm501_device_release;
619
620 smdev->pdev.name = name;
621 smdev->pdev.id = sm->pdev_id;
622 smdev->pdev.resource = (struct resource *)(smdev+1);
623 smdev->pdev.num_resources = res_count;
624
625 smdev->pdev.dev.parent = sm->dev;
626
627 return &smdev->pdev;
628}
629
630/* sm501_register_device
631 *
632 * Register a platform device created with sm501_create_subdev()
633*/
634
635static int sm501_register_device(struct sm501_devdata *sm,
636 struct platform_device *pdev)
637{
638 struct sm501_device *smdev = to_sm_device(pdev);
639 int ptr;
640 int ret;
641
642 for (ptr = 0; ptr < pdev->num_resources; ptr++) {
643 printk("%s[%d] flags %08lx: %08llx..%08llx\n",
644 pdev->name, ptr,
645 pdev->resource[ptr].flags,
646 (unsigned long long)pdev->resource[ptr].start,
647 (unsigned long long)pdev->resource[ptr].end);
648 }
649
650 ret = platform_device_register(pdev);
651
652 if (ret >= 0) {
653 dev_dbg(sm->dev, "registered %s\n", pdev->name);
654 list_add_tail(&smdev->list, &sm->devices);
655 } else
656 dev_err(sm->dev, "error registering %s (%d)\n",
657 pdev->name, ret);
658
659 return ret;
660}
661
662/* sm501_create_subio
663 *
664 * Fill in an IO resource for a sub device
665*/
666
667static void sm501_create_subio(struct sm501_devdata *sm,
668 struct resource *res,
669 resource_size_t offs,
670 resource_size_t size)
671{
672 res->flags = IORESOURCE_MEM;
673 res->parent = sm->io_res;
674 res->start = sm->io_res->start + offs;
675 res->end = res->start + size - 1;
676}
677
678/* sm501_create_mem
679 *
680 * Fill in an MEM resource for a sub device
681*/
682
683static void sm501_create_mem(struct sm501_devdata *sm,
684 struct resource *res,
685 resource_size_t *offs,
686 resource_size_t size)
687{
688 *offs -= size; /* adjust memory size */
689
690 res->flags = IORESOURCE_MEM;
691 res->parent = sm->mem_res;
692 res->start = sm->mem_res->start + *offs;
693 res->end = res->start + size - 1;
694}
695
696/* sm501_create_irq
697 *
698 * Fill in an IRQ resource for a sub device
699*/
700
701static void sm501_create_irq(struct sm501_devdata *sm,
702 struct resource *res)
703{
704 res->flags = IORESOURCE_IRQ;
705 res->parent = NULL;
706 res->start = res->end = sm->irq;
707}
708
709static int sm501_register_usbhost(struct sm501_devdata *sm,
710 resource_size_t *mem_avail)
711{
712 struct platform_device *pdev;
713
714 pdev = sm501_create_subdev(sm, "sm501-usb", 3);
715 if (!pdev)
716 return -ENOMEM;
717
718 sm501_create_subio(sm, &pdev->resource[0], 0x40000, 0x20000);
719 sm501_create_mem(sm, &pdev->resource[1], mem_avail, 256*1024);
720 sm501_create_irq(sm, &pdev->resource[2]);
721
722 return sm501_register_device(sm, pdev);
723}
724
725static int sm501_register_display(struct sm501_devdata *sm,
726 resource_size_t *mem_avail)
727{
728 struct platform_device *pdev;
729
730 pdev = sm501_create_subdev(sm, "sm501-fb", 4);
731 if (!pdev)
732 return -ENOMEM;
733
734 sm501_create_subio(sm, &pdev->resource[0], 0x80000, 0x10000);
735 sm501_create_subio(sm, &pdev->resource[1], 0x100000, 0x50000);
736 sm501_create_mem(sm, &pdev->resource[2], mem_avail, *mem_avail);
737 sm501_create_irq(sm, &pdev->resource[3]);
738
739 return sm501_register_device(sm, pdev);
740}
741
742/* sm501_dbg_regs
743 *
744 * Debug attribute to attach to parent device to show core registers
745*/
746
747static ssize_t sm501_dbg_regs(struct device *dev,
748 struct device_attribute *attr, char *buff)
749{
750 struct sm501_devdata *sm = dev_get_drvdata(dev) ;
751 unsigned int reg;
752 char *ptr = buff;
753 int ret;
754
755 for (reg = 0x00; reg < 0x70; reg += 4) {
756 ret = sprintf(ptr, "%08x = %08x\n",
757 reg, readl(sm->regs + reg));
758 ptr += ret;
759 }
760
761 return ptr - buff;
762}
763
764
765static DEVICE_ATTR(dbg_regs, 0666, sm501_dbg_regs, NULL);
766
767/* sm501_init_reg
768 *
769 * Helper function for the init code to setup a register
770*/
771
772static inline void sm501_init_reg(struct sm501_devdata *sm,
773 unsigned long reg,
774 struct sm501_reg_init *r)
775{
776 unsigned long tmp;
777
778 tmp = readl(sm->regs + reg);
779 tmp |= r->set;
780 tmp &= ~r->mask;
781 writel(tmp, sm->regs + reg);
782}
783
784/* sm501_init_regs
785 *
786 * Setup core register values
787*/
788
789static void sm501_init_regs(struct sm501_devdata *sm,
790 struct sm501_initdata *init)
791{
792 sm501_misc_control(sm->dev,
793 init->misc_control.set,
794 init->misc_control.mask);
795
796 sm501_init_reg(sm, SM501_MISC_TIMING, &init->misc_timing);
797 sm501_init_reg(sm, SM501_GPIO31_0_CONTROL, &init->gpio_low);
798 sm501_init_reg(sm, SM501_GPIO63_32_CONTROL, &init->gpio_high);
799
800 if (init->mclk) {
801 dev_info(sm->dev, "setting MCLK to %ld\n", init->mclk);
802 sm501_set_clock(sm->dev, SM501_CLOCK_MCLK, init->mclk);
803 }
804
805 if (init->m1xclk) {
806 dev_info(sm->dev, "setting M1XCLK to %ld\n", init->m1xclk);
807 sm501_set_clock(sm->dev, SM501_CLOCK_M1XCLK, init->m1xclk);
808 }
809}
810
811static unsigned int sm501_mem_local[] = {
812 [0] = 4*1024*1024,
813 [1] = 8*1024*1024,
814 [2] = 16*1024*1024,
815 [3] = 32*1024*1024,
816 [4] = 64*1024*1024,
817 [5] = 2*1024*1024,
818};
819
820/* sm501_init_dev
821 *
822 * Common init code for an SM501
823*/
824
825static int sm501_init_dev(struct sm501_devdata *sm)
826{
827 resource_size_t mem_avail;
828 unsigned long dramctrl;
829 int ret;
830
831 mutex_init(&sm->clock_lock);
832 spin_lock_init(&sm->reg_lock);
833
834 INIT_LIST_HEAD(&sm->devices);
835
836 dramctrl = readl(sm->regs + SM501_DRAM_CONTROL);
837
838 mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7];
839
840 dev_info(sm->dev, "SM501 At %p: Version %08x, %ld Mb, IRQ %d\n",
841 sm->regs, readl(sm->regs + SM501_DEVICEID),
842 (unsigned long)mem_avail >> 20, sm->irq);
843
844 dev_info(sm->dev, "CurrentGate %08x\n", readl(sm->regs+0x38));
845 dev_info(sm->dev, "CurrentClock %08x\n", readl(sm->regs+0x3c));
846 dev_info(sm->dev, "PowerModeControl %08x\n", readl(sm->regs+0x54));
847
848 ret = device_create_file(sm->dev, &dev_attr_dbg_regs);
849 if (ret)
850 dev_err(sm->dev, "failed to create debug regs file\n");
851
852 sm501_dump_clk(sm);
853
854 /* check to see if we have some device initialisation */
855
856 if (sm->platdata) {
857 struct sm501_platdata *pdata = sm->platdata;
858
859 if (pdata->init) {
860 sm501_init_regs(sm, sm->platdata->init);
861
862 if (pdata->init->devices & SM501_USE_USB_HOST)
863 sm501_register_usbhost(sm, &mem_avail);
864 }
865 }
866
867 /* always create a framebuffer */
868 sm501_register_display(sm, &mem_avail);
869
870 return 0;
871}
872
873static int sm501_plat_probe(struct platform_device *dev)
874{
875 struct sm501_devdata *sm;
876 int err;
877
878 sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
879 if (sm == NULL) {
880 dev_err(&dev->dev, "no memory for device data\n");
881 err = -ENOMEM;
882 goto err1;
883 }
884
885 sm->dev = &dev->dev;
886 sm->pdev_id = dev->id;
887 sm->irq = platform_get_irq(dev, 0);
888 sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
889 sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
890 sm->platdata = dev->dev.platform_data;
891
892 if (sm->irq < 0) {
893 dev_err(&dev->dev, "failed to get irq resource\n");
894 err = sm->irq;
895 goto err_res;
896 }
897
898 if (sm->io_res == NULL || sm->mem_res == NULL) {
899 dev_err(&dev->dev, "failed to get IO resource\n");
900 err = -ENOENT;
901 goto err_res;
902 }
903
904 sm->regs_claim = request_mem_region(sm->io_res->start,
905 0x100, "sm501");
906
907 if (sm->regs_claim == NULL) {
908 dev_err(&dev->dev, "cannot claim registers\n");
909 err= -EBUSY;
910 goto err_res;
911 }
912
913 platform_set_drvdata(dev, sm);
914
915 sm->regs = ioremap(sm->io_res->start,
916 (sm->io_res->end - sm->io_res->start) - 1);
917
918 if (sm->regs == NULL) {
919 dev_err(&dev->dev, "cannot remap registers\n");
920 err = -EIO;
921 goto err_claim;
922 }
923
924 return sm501_init_dev(sm);
925
926 err_claim:
927 release_resource(sm->regs_claim);
928 kfree(sm->regs_claim);
929 err_res:
930 kfree(sm);
931 err1:
932 return err;
933
934}
935
936/* Initialisation data for PCI devices */
937
938static struct sm501_initdata sm501_pci_initdata = {
939 .gpio_high = {
940 .set = 0x3F000000, /* 24bit panel */
941 .mask = 0x0,
942 },
943 .misc_timing = {
944 .set = 0x010100, /* SDRAM timing */
945 .mask = 0x1F1F00,
946 },
947 .misc_control = {
948 .set = SM501_MISC_PNL_24BIT,
949 .mask = 0,
950 },
951
952 .devices = SM501_USE_ALL,
953 .mclk = 100 * MHZ,
954 .m1xclk = 160 * MHZ,
955};
956
957static struct sm501_platdata_fbsub sm501_pdata_fbsub = {
958 .flags = (SM501FB_FLAG_USE_INIT_MODE |
959 SM501FB_FLAG_USE_HWCURSOR |
960 SM501FB_FLAG_USE_HWACCEL |
961 SM501FB_FLAG_DISABLE_AT_EXIT),
962};
963
964static struct sm501_platdata_fb sm501_fb_pdata = {
965 .fb_route = SM501_FB_OWN,
966 .fb_crt = &sm501_pdata_fbsub,
967 .fb_pnl = &sm501_pdata_fbsub,
968};
969
970static struct sm501_platdata sm501_pci_platdata = {
971 .init = &sm501_pci_initdata,
972 .fb = &sm501_fb_pdata,
973};
974
975static int sm501_pci_probe(struct pci_dev *dev,
976 const struct pci_device_id *id)
977{
978 struct sm501_devdata *sm;
979 int err;
980
981 sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
982 if (sm == NULL) {
983 dev_err(&dev->dev, "no memory for device data\n");
984 err = -ENOMEM;
985 goto err1;
986 }
987
988 /* set a default set of platform data */
989 dev->dev.platform_data = sm->platdata = &sm501_pci_platdata;
990
991 /* set a hopefully unique id for our child platform devices */
992 sm->pdev_id = 32 + dev->devfn;
993
994 pci_set_drvdata(dev, sm);
995
996 err = pci_enable_device(dev);
997 if (err) {
998 dev_err(&dev->dev, "cannot enable device\n");
999 goto err2;
1000 }
1001
1002 sm->dev = &dev->dev;
1003 sm->irq = dev->irq;
1004
1005#ifdef __BIG_ENDIAN
1006 /* if the system is big-endian, we most probably have a
1007 * translation in the IO layer making the PCI bus little endian
1008 * so make the framebuffer swapped pixels */
1009
1010 sm501_fb_pdata.flags |= SM501_FBPD_SWAP_FB_ENDIAN;
1011#endif
1012
1013 /* check our resources */
1014
1015 if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) {
1016 dev_err(&dev->dev, "region #0 is not memory?\n");
1017 err = -EINVAL;
1018 goto err3;
1019 }
1020
1021 if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM)) {
1022 dev_err(&dev->dev, "region #1 is not memory?\n");
1023 err = -EINVAL;
1024 goto err3;
1025 }
1026
1027 /* make our resources ready for sharing */
1028
1029 sm->io_res = &dev->resource[1];
1030 sm->mem_res = &dev->resource[0];
1031
1032 sm->regs_claim = request_mem_region(sm->io_res->start,
1033 0x100, "sm501");
1034 if (sm->regs_claim == NULL) {
1035 dev_err(&dev->dev, "cannot claim registers\n");
1036 err= -EBUSY;
1037 goto err3;
1038 }
1039
1040 sm->regs = ioremap(pci_resource_start(dev, 1),
1041 pci_resource_len(dev, 1));
1042
1043 if (sm->regs == NULL) {
1044 dev_err(&dev->dev, "cannot remap registers\n");
1045 err = -EIO;
1046 goto err4;
1047 }
1048
1049 sm501_init_dev(sm);
1050 return 0;
1051
1052 err4:
1053 release_resource(sm->regs_claim);
1054 kfree(sm->regs_claim);
1055 err3:
1056 pci_disable_device(dev);
1057 err2:
1058 pci_set_drvdata(dev, NULL);
1059 kfree(sm);
1060 err1:
1061 return err;
1062}
1063
1064static void sm501_remove_sub(struct sm501_devdata *sm,
1065 struct sm501_device *smdev)
1066{
1067 list_del(&smdev->list);
1068 platform_device_unregister(&smdev->pdev);
1069}
1070
1071static void sm501_dev_remove(struct sm501_devdata *sm)
1072{
1073 struct sm501_device *smdev, *tmp;
1074
1075 list_for_each_entry_safe(smdev, tmp, &sm->devices, list)
1076 sm501_remove_sub(sm, smdev);
1077
1078 device_remove_file(sm->dev, &dev_attr_dbg_regs);
1079}
1080
1081static void sm501_pci_remove(struct pci_dev *dev)
1082{
1083 struct sm501_devdata *sm = pci_get_drvdata(dev);
1084
1085 sm501_dev_remove(sm);
1086 iounmap(sm->regs);
1087
1088 release_resource(sm->regs_claim);
1089 kfree(sm->regs_claim);
1090
1091 pci_set_drvdata(dev, NULL);
1092 pci_disable_device(dev);
1093}
1094
1095static int sm501_plat_remove(struct platform_device *dev)
1096{
1097 struct sm501_devdata *sm = platform_get_drvdata(dev);
1098
1099 sm501_dev_remove(sm);
1100 iounmap(sm->regs);
1101
1102 release_resource(sm->regs_claim);
1103 kfree(sm->regs_claim);
1104
1105 return 0;
1106}
1107
1108static struct pci_device_id sm501_pci_tbl[] = {
1109 { 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1110 { 0, },
1111};
1112
1113MODULE_DEVICE_TABLE(pci, sm501_pci_tbl);
1114
1115static struct pci_driver sm501_pci_drv = {
1116 .name = "sm501",
1117 .id_table = sm501_pci_tbl,
1118 .probe = sm501_pci_probe,
1119 .remove = sm501_pci_remove,
1120};
1121
1122static struct platform_driver sm501_plat_drv = {
1123 .driver = {
1124 .name = "sm501",
1125 .owner = THIS_MODULE,
1126 },
1127 .probe = sm501_plat_probe,
1128 .remove = sm501_plat_remove,
1129};
1130
1131static int __init sm501_base_init(void)
1132{
1133 platform_driver_register(&sm501_plat_drv);
1134 return pci_module_init(&sm501_pci_drv);
1135}
1136
1137static void __exit sm501_base_exit(void)
1138{
1139 platform_driver_unregister(&sm501_plat_drv);
1140 pci_unregister_driver(&sm501_pci_drv);
1141}
1142
1143module_init(sm501_base_init);
1144module_exit(sm501_base_exit);
1145
1146MODULE_DESCRIPTION("SM501 Core Driver");
1147MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Vincent Sanders");
1148MODULE_LICENSE("GPL v2");
diff --git a/include/linux/sm501-regs.h b/include/linux/sm501-regs.h
new file mode 100644
index 000000000000..cc9be4a11861
--- /dev/null
+++ b/include/linux/sm501-regs.h
@@ -0,0 +1,357 @@
1/* sm501-regs.h
2 *
3 * Copyright 2006 Simtec Electronics
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Silicon Motion SM501 register definitions
10*/
11
12/* System Configuration area */
13/* System config base */
14#define SM501_SYS_CONFIG (0x000000)
15
16/* config 1 */
17#define SM501_SYSTEM_CONTROL (0x000000)
18#define SM501_MISC_CONTROL (0x000004)
19
20#define SM501_MISC_BUS_SH (0x0)
21#define SM501_MISC_BUS_PCI (0x1)
22#define SM501_MISC_BUS_XSCALE (0x2)
23#define SM501_MISC_BUS_NEC (0x6)
24#define SM501_MISC_BUS_MASK (0x7)
25
26#define SM501_MISC_VR_62MB (1<<3)
27#define SM501_MISC_CDR_RESET (1<<7)
28#define SM501_MISC_USB_LB (1<<8)
29#define SM501_MISC_USB_SLAVE (1<<9)
30#define SM501_MISC_BL_1 (1<<10)
31#define SM501_MISC_MC (1<<11)
32#define SM501_MISC_DAC_POWER (1<<12)
33#define SM501_MISC_IRQ_INVERT (1<<16)
34#define SM501_MISC_SH (1<<17)
35
36#define SM501_MISC_HOLD_EMPTY (0<<18)
37#define SM501_MISC_HOLD_8 (1<<18)
38#define SM501_MISC_HOLD_16 (2<<18)
39#define SM501_MISC_HOLD_24 (3<<18)
40#define SM501_MISC_HOLD_32 (4<<18)
41#define SM501_MISC_HOLD_MASK (7<<18)
42
43#define SM501_MISC_FREQ_12 (1<<24)
44#define SM501_MISC_PNL_24BIT (1<<25)
45#define SM501_MISC_8051_LE (1<<26)
46
47
48
49#define SM501_GPIO31_0_CONTROL (0x000008)
50#define SM501_GPIO63_32_CONTROL (0x00000C)
51#define SM501_DRAM_CONTROL (0x000010)
52
53/* command list */
54#define SM501_ARBTRTN_CONTROL (0x000014)
55
56/* command list */
57#define SM501_COMMAND_LIST_STATUS (0x000024)
58
59/* interrupt debug */
60#define SM501_RAW_IRQ_STATUS (0x000028)
61#define SM501_RAW_IRQ_CLEAR (0x000028)
62#define SM501_IRQ_STATUS (0x00002C)
63#define SM501_IRQ_MASK (0x000030)
64#define SM501_DEBUG_CONTROL (0x000034)
65
66/* power management */
67#define SM501_CURRENT_GATE (0x000038)
68#define SM501_CURRENT_CLOCK (0x00003C)
69#define SM501_POWER_MODE_0_GATE (0x000040)
70#define SM501_POWER_MODE_0_CLOCK (0x000044)
71#define SM501_POWER_MODE_1_GATE (0x000048)
72#define SM501_POWER_MODE_1_CLOCK (0x00004C)
73#define SM501_SLEEP_MODE_GATE (0x000050)
74#define SM501_POWER_MODE_CONTROL (0x000054)
75
76/* power gates for units within the 501 */
77#define SM501_GATE_HOST (0)
78#define SM501_GATE_MEMORY (1)
79#define SM501_GATE_DISPLAY (2)
80#define SM501_GATE_2D_ENGINE (3)
81#define SM501_GATE_CSC (4)
82#define SM501_GATE_ZVPORT (5)
83#define SM501_GATE_GPIO (6)
84#define SM501_GATE_UART0 (7)
85#define SM501_GATE_UART1 (8)
86#define SM501_GATE_SSP (10)
87#define SM501_GATE_USB_HOST (11)
88#define SM501_GATE_USB_GADGET (12)
89#define SM501_GATE_UCONTROLLER (17)
90#define SM501_GATE_AC97 (18)
91
92/* panel clock */
93#define SM501_CLOCK_P2XCLK (24)
94/* crt clock */
95#define SM501_CLOCK_V2XCLK (16)
96/* main clock */
97#define SM501_CLOCK_MCLK (8)
98/* SDRAM controller clock */
99#define SM501_CLOCK_M1XCLK (0)
100
101/* config 2 */
102#define SM501_PCI_MASTER_BASE (0x000058)
103#define SM501_ENDIAN_CONTROL (0x00005C)
104#define SM501_DEVICEID (0x000060)
105/* 0x050100A0 */
106
107#define SM501_PLLCLOCK_COUNT (0x000064)
108#define SM501_MISC_TIMING (0x000068)
109#define SM501_CURRENT_SDRAM_CLOCK (0x00006C)
110
111/* GPIO base */
112#define SM501_GPIO (0x010000)
113#define SM501_GPIO_DATA_LOW (0x00)
114#define SM501_GPIO_DATA_HIGH (0x04)
115#define SM501_GPIO_DDR_LOW (0x08)
116#define SM501_GPIO_DDR_HIGH (0x0C)
117#define SM501_GPIO_IRQ_SETUP (0x10)
118#define SM501_GPIO_IRQ_STATUS (0x14)
119#define SM501_GPIO_IRQ_RESET (0x14)
120
121/* I2C controller base */
122#define SM501_I2C (0x010040)
123#define SM501_I2C_BYTE_COUNT (0x00)
124#define SM501_I2C_CONTROL (0x01)
125#define SM501_I2C_STATUS (0x02)
126#define SM501_I2C_RESET (0x02)
127#define SM501_I2C_SLAVE_ADDRESS (0x03)
128#define SM501_I2C_DATA (0x04)
129
130/* SSP base */
131#define SM501_SSP (0x020000)
132
133/* Uart 0 base */
134#define SM501_UART0 (0x030000)
135
136/* Uart 1 base */
137#define SM501_UART1 (0x030020)
138
139/* USB host port base */
140#define SM501_USB_HOST (0x040000)
141
142/* USB slave/gadget base */
143#define SM501_USB_GADGET (0x060000)
144
145/* USB slave/gadget data port base */
146#define SM501_USB_GADGET_DATA (0x070000)
147
148/* Display contoller/video engine base */
149#define SM501_DC (0x080000)
150
151/* common defines for the SM501 address registers */
152#define SM501_ADDR_FLIP (1<<31)
153#define SM501_ADDR_EXT (1<<27)
154#define SM501_ADDR_CS1 (1<<26)
155#define SM501_ADDR_MASK (0x3f << 26)
156
157#define SM501_FIFO_MASK (0x3 << 16)
158#define SM501_FIFO_1 (0x0 << 16)
159#define SM501_FIFO_3 (0x1 << 16)
160#define SM501_FIFO_7 (0x2 << 16)
161#define SM501_FIFO_11 (0x3 << 16)
162
163/* common registers for panel and the crt */
164#define SM501_OFF_DC_H_TOT (0x000)
165#define SM501_OFF_DC_V_TOT (0x008)
166#define SM501_OFF_DC_H_SYNC (0x004)
167#define SM501_OFF_DC_V_SYNC (0x00C)
168
169#define SM501_DC_PANEL_CONTROL (0x000)
170
171#define SM501_DC_PANEL_CONTROL_FPEN (1<<27)
172#define SM501_DC_PANEL_CONTROL_BIAS (1<<26)
173#define SM501_DC_PANEL_CONTROL_DATA (1<<25)
174#define SM501_DC_PANEL_CONTROL_VDD (1<<24)
175#define SM501_DC_PANEL_CONTROL_DP (1<<23)
176
177#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21)
178#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21)
179#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21)
180
181#define SM501_DC_PANEL_CONTROL_DE (1<<20)
182
183#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18)
184#define SM501_DC_PANEL_CONTROL_LCD_STN8 (1<<18)
185#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
186
187#define SM501_DC_PANEL_CONTROL_CP (1<<14)
188#define SM501_DC_PANEL_CONTROL_VSP (1<<13)
189#define SM501_DC_PANEL_CONTROL_HSP (1<<12)
190#define SM501_DC_PANEL_CONTROL_CK (1<<9)
191#define SM501_DC_PANEL_CONTROL_TE (1<<8)
192#define SM501_DC_PANEL_CONTROL_VPD (1<<7)
193#define SM501_DC_PANEL_CONTROL_VP (1<<6)
194#define SM501_DC_PANEL_CONTROL_HPD (1<<5)
195#define SM501_DC_PANEL_CONTROL_HP (1<<4)
196#define SM501_DC_PANEL_CONTROL_GAMMA (1<<3)
197#define SM501_DC_PANEL_CONTROL_EN (1<<2)
198
199#define SM501_DC_PANEL_CONTROL_8BPP (0<<0)
200#define SM501_DC_PANEL_CONTROL_16BPP (1<<0)
201#define SM501_DC_PANEL_CONTROL_32BPP (2<<0)
202
203
204#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
205#define SM501_DC_PANEL_COLOR_KEY (0x008)
206#define SM501_DC_PANEL_FB_ADDR (0x00C)
207#define SM501_DC_PANEL_FB_OFFSET (0x010)
208#define SM501_DC_PANEL_FB_WIDTH (0x014)
209#define SM501_DC_PANEL_FB_HEIGHT (0x018)
210#define SM501_DC_PANEL_TL_LOC (0x01C)
211#define SM501_DC_PANEL_BR_LOC (0x020)
212#define SM501_DC_PANEL_H_TOT (0x024)
213#define SM501_DC_PANEL_H_SYNC (0x028)
214#define SM501_DC_PANEL_V_TOT (0x02C)
215#define SM501_DC_PANEL_V_SYNC (0x030)
216#define SM501_DC_PANEL_CUR_LINE (0x034)
217
218#define SM501_DC_VIDEO_CONTROL (0x040)
219#define SM501_DC_VIDEO_FB0_ADDR (0x044)
220#define SM501_DC_VIDEO_FB_WIDTH (0x048)
221#define SM501_DC_VIDEO_FB0_LAST_ADDR (0x04C)
222#define SM501_DC_VIDEO_TL_LOC (0x050)
223#define SM501_DC_VIDEO_BR_LOC (0x054)
224#define SM501_DC_VIDEO_SCALE (0x058)
225#define SM501_DC_VIDEO_INIT_SCALE (0x05C)
226#define SM501_DC_VIDEO_YUV_CONSTANTS (0x060)
227#define SM501_DC_VIDEO_FB1_ADDR (0x064)
228#define SM501_DC_VIDEO_FB1_LAST_ADDR (0x068)
229
230#define SM501_DC_VIDEO_ALPHA_CONTROL (0x080)
231#define SM501_DC_VIDEO_ALPHA_FB_ADDR (0x084)
232#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
233#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR (0x08C)
234#define SM501_DC_VIDEO_ALPHA_TL_LOC (0x090)
235#define SM501_DC_VIDEO_ALPHA_BR_LOC (0x094)
236#define SM501_DC_VIDEO_ALPHA_SCALE (0x098)
237#define SM501_DC_VIDEO_ALPHA_INIT_SCALE (0x09C)
238#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY (0x0A0)
239#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP (0x0A4)
240
241#define SM501_DC_PANEL_HWC_BASE (0x0F0)
242#define SM501_DC_PANEL_HWC_ADDR (0x0F0)
243#define SM501_DC_PANEL_HWC_LOC (0x0F4)
244#define SM501_DC_PANEL_HWC_COLOR_1_2 (0x0F8)
245#define SM501_DC_PANEL_HWC_COLOR_3 (0x0FC)
246
247#define SM501_HWC_EN (1<<31)
248
249#define SM501_OFF_HWC_ADDR (0x00)
250#define SM501_OFF_HWC_LOC (0x04)
251#define SM501_OFF_HWC_COLOR_1_2 (0x08)
252#define SM501_OFF_HWC_COLOR_3 (0x0C)
253
254#define SM501_DC_ALPHA_CONTROL (0x100)
255#define SM501_DC_ALPHA_FB_ADDR (0x104)
256#define SM501_DC_ALPHA_FB_OFFSET (0x108)
257#define SM501_DC_ALPHA_TL_LOC (0x10C)
258#define SM501_DC_ALPHA_BR_LOC (0x110)
259#define SM501_DC_ALPHA_CHROMA_KEY (0x114)
260#define SM501_DC_ALPHA_COLOR_LOOKUP (0x118)
261
262#define SM501_DC_CRT_CONTROL (0x200)
263
264#define SM501_DC_CRT_CONTROL_TVP (1<<15)
265#define SM501_DC_CRT_CONTROL_CP (1<<14)
266#define SM501_DC_CRT_CONTROL_VSP (1<<13)
267#define SM501_DC_CRT_CONTROL_HSP (1<<12)
268#define SM501_DC_CRT_CONTROL_VS (1<<11)
269#define SM501_DC_CRT_CONTROL_BLANK (1<<10)
270#define SM501_DC_CRT_CONTROL_SEL (1<<9)
271#define SM501_DC_CRT_CONTROL_TE (1<<8)
272#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
273#define SM501_DC_CRT_CONTROL_GAMMA (1<<3)
274#define SM501_DC_CRT_CONTROL_ENABLE (1<<2)
275
276#define SM501_DC_CRT_CONTROL_8BPP (0<<0)
277#define SM501_DC_CRT_CONTROL_16BPP (1<<0)
278#define SM501_DC_CRT_CONTROL_32BPP (2<<0)
279
280#define SM501_DC_CRT_FB_ADDR (0x204)
281#define SM501_DC_CRT_FB_OFFSET (0x208)
282#define SM501_DC_CRT_H_TOT (0x20C)
283#define SM501_DC_CRT_H_SYNC (0x210)
284#define SM501_DC_CRT_V_TOT (0x214)
285#define SM501_DC_CRT_V_SYNC (0x218)
286#define SM501_DC_CRT_SIGNATURE_ANALYZER (0x21C)
287#define SM501_DC_CRT_CUR_LINE (0x220)
288#define SM501_DC_CRT_MONITOR_DETECT (0x224)
289
290#define SM501_DC_CRT_HWC_BASE (0x230)
291#define SM501_DC_CRT_HWC_ADDR (0x230)
292#define SM501_DC_CRT_HWC_LOC (0x234)
293#define SM501_DC_CRT_HWC_COLOR_1_2 (0x238)
294#define SM501_DC_CRT_HWC_COLOR_3 (0x23C)
295
296#define SM501_DC_PANEL_PALETTE (0x400)
297
298#define SM501_DC_VIDEO_PALETTE (0x800)
299
300#define SM501_DC_CRT_PALETTE (0xC00)
301
302/* Zoom Video port base */
303#define SM501_ZVPORT (0x090000)
304
305/* AC97/I2S base */
306#define SM501_AC97 (0x0A0000)
307
308/* 8051 micro controller base */
309#define SM501_UCONTROLLER (0x0B0000)
310
311/* 8051 micro controller SRAM base */
312#define SM501_UCONTROLLER_SRAM (0x0C0000)
313
314/* DMA base */
315#define SM501_DMA (0x0D0000)
316
317/* 2d engine base */
318#define SM501_2D_ENGINE (0x100000)
319#define SM501_2D_SOURCE (0x00)
320#define SM501_2D_DESTINATION (0x04)
321#define SM501_2D_DIMENSION (0x08)
322#define SM501_2D_CONTROL (0x0C)
323#define SM501_2D_PITCH (0x10)
324#define SM501_2D_FOREGROUND (0x14)
325#define SM501_2D_BACKGROUND (0x18)
326#define SM501_2D_STRETCH (0x1C)
327#define SM501_2D_COLOR_COMPARE (0x20)
328#define SM501_2D_COLOR_COMPARE_MASK (0x24)
329#define SM501_2D_MASK (0x28)
330#define SM501_2D_CLIP_TL (0x2C)
331#define SM501_2D_CLIP_BR (0x30)
332#define SM501_2D_MONO_PATTERN_LOW (0x34)
333#define SM501_2D_MONO_PATTERN_HIGH (0x38)
334#define SM501_2D_WINDOW_WIDTH (0x3C)
335#define SM501_2D_SOURCE_BASE (0x40)
336#define SM501_2D_DESTINATION_BASE (0x44)
337#define SM501_2D_ALPHA (0x48)
338#define SM501_2D_WRAP (0x4C)
339#define SM501_2D_STATUS (0x50)
340
341#define SM501_CSC_Y_SOURCE_BASE (0xC8)
342#define SM501_CSC_CONSTANTS (0xCC)
343#define SM501_CSC_Y_SOURCE_X (0xD0)
344#define SM501_CSC_Y_SOURCE_Y (0xD4)
345#define SM501_CSC_U_SOURCE_BASE (0xD8)
346#define SM501_CSC_V_SOURCE_BASE (0xDC)
347#define SM501_CSC_SOURCE_DIMENSION (0xE0)
348#define SM501_CSC_SOURCE_PITCH (0xE4)
349#define SM501_CSC_DESTINATION (0xE8)
350#define SM501_CSC_DESTINATION_DIMENSION (0xEC)
351#define SM501_CSC_DESTINATION_PITCH (0xF0)
352#define SM501_CSC_SCALE_FACTOR (0xF4)
353#define SM501_CSC_DESTINATION_BASE (0xF8)
354#define SM501_CSC_CONTROL (0xFC)
355
356/* 2d engine data port base */
357#define SM501_2D_ENGINE_DATA (0x110000)
diff --git a/include/linux/sm501.h b/include/linux/sm501.h
new file mode 100644
index 000000000000..9e3aaad6fe4d
--- /dev/null
+++ b/include/linux/sm501.h
@@ -0,0 +1,170 @@
1/* include/linux/sm501.h
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * Vincent Sanders <vince@simtec.co.uk>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21extern int sm501_unit_power(struct device *dev,
22 unsigned int unit, unsigned int to);
23
24extern unsigned long sm501_set_clock(struct device *dev,
25 int clksrc, unsigned long freq);
26
27extern unsigned long sm501_find_clock(int clksrc, unsigned long req_freq);
28
29/* sm501_misc_control
30 *
31 * Modify the SM501's MISC_CONTROL register
32*/
33
34extern int sm501_misc_control(struct device *dev,
35 unsigned long set, unsigned long clear);
36
37/* sm501_modify_reg
38 *
39 * Modify a register in the SM501 which may be shared with other
40 * drivers.
41*/
42
43extern unsigned long sm501_modify_reg(struct device *dev,
44 unsigned long reg,
45 unsigned long set,
46 unsigned long clear);
47
48/* sm501_gpio_set
49 *
50 * set the state of the given GPIO line
51*/
52
53extern void sm501_gpio_set(struct device *dev,
54 unsigned long gpio,
55 unsigned int to,
56 unsigned int dir);
57
58/* sm501_gpio_get
59 *
60 * get the state of the given GPIO line
61*/
62
63extern unsigned long sm501_gpio_get(struct device *dev,
64 unsigned long gpio);
65
66
67/* Platform data definitions */
68
69#define SM501FB_FLAG_USE_INIT_MODE (1<<0)
70#define SM501FB_FLAG_DISABLE_AT_EXIT (1<<1)
71#define SM501FB_FLAG_USE_HWCURSOR (1<<2)
72#define SM501FB_FLAG_USE_HWACCEL (1<<3)
73
74struct sm501_platdata_fbsub {
75 struct fb_videomode *def_mode;
76 unsigned int def_bpp;
77 unsigned long max_mem;
78 unsigned int flags;
79};
80
81enum sm501_fb_routing {
82 SM501_FB_OWN = 0, /* CRT=>CRT, Panel=>Panel */
83 SM501_FB_CRT_PANEL = 1, /* Panel=>CRT, Panel=>Panel */
84};
85
86/* sm501_platdata_fb flag field bit definitions */
87
88#define SM501_FBPD_SWAP_FB_ENDIAN (1<<0) /* need to endian swap */
89
90/* sm501_platdata_fb
91 *
92 * configuration data for the framebuffer driver
93*/
94
95struct sm501_platdata_fb {
96 enum sm501_fb_routing fb_route;
97 unsigned int flags;
98 struct sm501_platdata_fbsub *fb_crt;
99 struct sm501_platdata_fbsub *fb_pnl;
100};
101
102/* gpio i2c */
103
104struct sm501_platdata_gpio_i2c {
105 unsigned int pin_sda;
106 unsigned int pin_scl;
107};
108
109/* sm501_initdata
110 *
111 * use for initialising values that may not have been setup
112 * before the driver is loaded.
113*/
114
115struct sm501_reg_init {
116 unsigned long set;
117 unsigned long mask;
118};
119
120#define SM501_USE_USB_HOST (1<<0)
121#define SM501_USE_USB_SLAVE (1<<1)
122#define SM501_USE_SSP0 (1<<2)
123#define SM501_USE_SSP1 (1<<3)
124#define SM501_USE_UART0 (1<<4)
125#define SM501_USE_UART1 (1<<5)
126#define SM501_USE_FBACCEL (1<<6)
127#define SM501_USE_AC97 (1<<7)
128#define SM501_USE_I2S (1<<8)
129
130#define SM501_USE_ALL (0xffffffff)
131
132struct sm501_initdata {
133 struct sm501_reg_init gpio_low;
134 struct sm501_reg_init gpio_high;
135 struct sm501_reg_init misc_timing;
136 struct sm501_reg_init misc_control;
137
138 unsigned long devices;
139 unsigned long mclk; /* non-zero to modify */
140 unsigned long m1xclk; /* non-zero to modify */
141};
142
143/* sm501_init_gpio
144 *
145 * default gpio settings
146*/
147
148struct sm501_init_gpio {
149 struct sm501_reg_init gpio_data_low;
150 struct sm501_reg_init gpio_data_high;
151 struct sm501_reg_init gpio_ddr_low;
152 struct sm501_reg_init gpio_ddr_high;
153};
154
155/* sm501_platdata
156 *
157 * This is passed with the platform device to allow the board
158 * to control the behaviour of the SM501 driver(s) which attach
159 * to the device.
160 *
161*/
162
163struct sm501_platdata {
164 struct sm501_initdata *init;
165 struct sm501_init_gpio *init_gpiop;
166 struct sm501_platdata_fb *fb;
167
168 struct sm501_platdata_gpio_i2c *gpio_i2c;
169 unsigned int gpio_i2c_nr;
170};