• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  linux/arch/arm/mach-integrator/integrator_cp.c
3  *
4  *  Copyright (C) 2003 Deep Blue Solutions Ltd
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License.
9  */
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/list.h>
14 #include <linux/platform_device.h>
15 #include <linux/dma-mapping.h>
16 #include <linux/string.h>
17 #include <linux/device.h>
18 #include <linux/amba/bus.h>
19 #include <linux/amba/kmi.h>
20 #include <linux/amba/clcd.h>
21 #include <linux/platform_data/video-clcd-versatile.h>
22 #include <linux/amba/mmci.h>
23 #include <linux/io.h>
24 #include <linux/irqchip.h>
25 #include <linux/gfp.h>
26 #include <linux/mtd/physmap.h>
27 #include <linux/of_irq.h>
28 #include <linux/of_address.h>
29 #include <linux/of_platform.h>
30 #include <linux/sys_soc.h>
31 #include <linux/sched_clock.h>
32 
33 #include <asm/setup.h>
34 #include <asm/mach-types.h>
35 #include <asm/mach/arch.h>
36 #include <asm/mach/irq.h>
37 #include <asm/mach/map.h>
38 #include <asm/mach/time.h>
39 
40 #include "hardware.h"
41 #include "cm.h"
42 #include "common.h"
43 
44 /* Base address to the CP controller */
45 static void __iomem *intcp_con_base;
46 
47 #define INTCP_PA_FLASH_BASE		0x24000000
48 
49 #define INTCP_PA_CLCD_BASE		0xc0000000
50 
51 #define INTCP_FLASHPROG			0x04
52 #define CINTEGRATOR_FLASHPROG_FLVPPEN	(1 << 0)
53 #define CINTEGRATOR_FLASHPROG_FLWREN	(1 << 1)
54 
55 /*
56  * Logical      Physical
57  * f1000000	10000000	Core module registers
58  * f1300000	13000000	Counter/Timer
59  * f1400000	14000000	Interrupt controller
60  * f1600000	16000000	UART 0
61  * f1700000	17000000	UART 1
62  * f1a00000	1a000000	Debug LEDs
63  * fc900000	c9000000	GPIO
64  * fca00000	ca000000	SIC
65  */
66 
67 static struct map_desc intcp_io_desc[] __initdata __maybe_unused = {
68 	{
69 		.virtual	= IO_ADDRESS(INTEGRATOR_HDR_BASE),
70 		.pfn		= __phys_to_pfn(INTEGRATOR_HDR_BASE),
71 		.length		= SZ_4K,
72 		.type		= MT_DEVICE
73 	}, {
74 		.virtual	= IO_ADDRESS(INTEGRATOR_CT_BASE),
75 		.pfn		= __phys_to_pfn(INTEGRATOR_CT_BASE),
76 		.length		= SZ_4K,
77 		.type		= MT_DEVICE
78 	}, {
79 		.virtual	= IO_ADDRESS(INTEGRATOR_IC_BASE),
80 		.pfn		= __phys_to_pfn(INTEGRATOR_IC_BASE),
81 		.length		= SZ_4K,
82 		.type		= MT_DEVICE
83 	}, {
84 		.virtual	= IO_ADDRESS(INTEGRATOR_UART0_BASE),
85 		.pfn		= __phys_to_pfn(INTEGRATOR_UART0_BASE),
86 		.length		= SZ_4K,
87 		.type		= MT_DEVICE
88 	}, {
89 		.virtual	= IO_ADDRESS(INTEGRATOR_DBG_BASE),
90 		.pfn		= __phys_to_pfn(INTEGRATOR_DBG_BASE),
91 		.length		= SZ_4K,
92 		.type		= MT_DEVICE
93 	}, {
94 		.virtual	= IO_ADDRESS(INTEGRATOR_CP_GPIO_BASE),
95 		.pfn		= __phys_to_pfn(INTEGRATOR_CP_GPIO_BASE),
96 		.length		= SZ_4K,
97 		.type		= MT_DEVICE
98 	}, {
99 		.virtual	= IO_ADDRESS(INTEGRATOR_CP_SIC_BASE),
100 		.pfn		= __phys_to_pfn(INTEGRATOR_CP_SIC_BASE),
101 		.length		= SZ_4K,
102 		.type		= MT_DEVICE
103 	}
104 };
105 
intcp_map_io(void)106 static void __init intcp_map_io(void)
107 {
108 	iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc));
109 }
110 
111 /*
112  * Flash handling.
113  */
intcp_flash_init(struct platform_device * dev)114 static int intcp_flash_init(struct platform_device *dev)
115 {
116 	u32 val;
117 
118 	val = readl(intcp_con_base + INTCP_FLASHPROG);
119 	val |= CINTEGRATOR_FLASHPROG_FLWREN;
120 	writel(val, intcp_con_base + INTCP_FLASHPROG);
121 
122 	return 0;
123 }
124 
intcp_flash_exit(struct platform_device * dev)125 static void intcp_flash_exit(struct platform_device *dev)
126 {
127 	u32 val;
128 
129 	val = readl(intcp_con_base + INTCP_FLASHPROG);
130 	val &= ~(CINTEGRATOR_FLASHPROG_FLVPPEN|CINTEGRATOR_FLASHPROG_FLWREN);
131 	writel(val, intcp_con_base + INTCP_FLASHPROG);
132 }
133 
intcp_flash_set_vpp(struct platform_device * pdev,int on)134 static void intcp_flash_set_vpp(struct platform_device *pdev, int on)
135 {
136 	u32 val;
137 
138 	val = readl(intcp_con_base + INTCP_FLASHPROG);
139 	if (on)
140 		val |= CINTEGRATOR_FLASHPROG_FLVPPEN;
141 	else
142 		val &= ~CINTEGRATOR_FLASHPROG_FLVPPEN;
143 	writel(val, intcp_con_base + INTCP_FLASHPROG);
144 }
145 
146 static struct physmap_flash_data intcp_flash_data = {
147 	.width		= 4,
148 	.init		= intcp_flash_init,
149 	.exit		= intcp_flash_exit,
150 	.set_vpp	= intcp_flash_set_vpp,
151 };
152 
153 /*
154  * It seems that the card insertion interrupt remains active after
155  * we've acknowledged it.  We therefore ignore the interrupt, and
156  * rely on reading it from the SIC.  This also means that we must
157  * clear the latched interrupt.
158  */
mmc_status(struct device * dev)159 static unsigned int mmc_status(struct device *dev)
160 {
161 	unsigned int status = readl(__io_address(0xca000000 + 4));
162 	writel(8, intcp_con_base + 8);
163 
164 	return status & 8;
165 }
166 
167 static struct mmci_platform_data mmc_data = {
168 	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
169 	.status		= mmc_status,
170 	.gpio_wp	= -1,
171 	.gpio_cd	= -1,
172 };
173 
174 /*
175  * CLCD support
176  */
177 /*
178  * Ensure VGA is selected.
179  */
cp_clcd_enable(struct clcd_fb * fb)180 static void cp_clcd_enable(struct clcd_fb *fb)
181 {
182 	struct fb_var_screeninfo *var = &fb->fb.var;
183 	u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2
184 			| CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1;
185 
186 	if (var->bits_per_pixel <= 8 ||
187 	    (var->bits_per_pixel == 16 && var->green.length == 5))
188 		/* Pseudocolor, RGB555, BGR555 */
189 		val |= CM_CTRL_LCDMUXSEL_VGA555_TFT555;
190 	else if (fb->fb.var.bits_per_pixel <= 16)
191 		/* truecolor RGB565 */
192 		val |= CM_CTRL_LCDMUXSEL_VGA565_TFT555;
193 	else
194 		val = 0; /* no idea for this, don't trust the docs */
195 
196 	cm_control(CM_CTRL_LCDMUXSEL_MASK|
197 		   CM_CTRL_LCDEN0|
198 		   CM_CTRL_LCDEN1|
199 		   CM_CTRL_STATIC1|
200 		   CM_CTRL_STATIC2|
201 		   CM_CTRL_STATIC|
202 		   CM_CTRL_n24BITEN, val);
203 }
204 
cp_clcd_setup(struct clcd_fb * fb)205 static int cp_clcd_setup(struct clcd_fb *fb)
206 {
207 	fb->panel = versatile_clcd_get_panel("VGA");
208 	if (!fb->panel)
209 		return -EINVAL;
210 
211 	return versatile_clcd_setup_dma(fb, SZ_1M);
212 }
213 
214 static struct clcd_board clcd_data = {
215 	.name		= "Integrator/CP",
216 	.caps		= CLCD_CAP_5551 | CLCD_CAP_RGB565 | CLCD_CAP_888,
217 	.check		= clcdfb_check,
218 	.decode		= clcdfb_decode,
219 	.enable		= cp_clcd_enable,
220 	.setup		= cp_clcd_setup,
221 	.mmap		= versatile_clcd_mmap_dma,
222 	.remove		= versatile_clcd_remove_dma,
223 };
224 
225 #define REFCOUNTER (__io_address(INTEGRATOR_HDR_BASE) + 0x28)
226 
intcp_read_sched_clock(void)227 static u64 notrace intcp_read_sched_clock(void)
228 {
229 	return readl(REFCOUNTER);
230 }
231 
intcp_init_early(void)232 static void __init intcp_init_early(void)
233 {
234 	sched_clock_register(intcp_read_sched_clock, 32, 24000000);
235 }
236 
intcp_init_irq_of(void)237 static void __init intcp_init_irq_of(void)
238 {
239 	cm_init();
240 	irqchip_init();
241 }
242 
243 /*
244  * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA
245  * and enforce the bus names since these are used for clock lookups.
246  */
247 static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = {
248 	OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE,
249 		"rtc", NULL),
250 	OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE,
251 		"uart0", NULL),
252 	OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE,
253 		"uart1", NULL),
254 	OF_DEV_AUXDATA("arm,primecell", KMI0_BASE,
255 		"kmi0", NULL),
256 	OF_DEV_AUXDATA("arm,primecell", KMI1_BASE,
257 		"kmi1", NULL),
258 	OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE,
259 		"mmci", &mmc_data),
260 	OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_AACI_BASE,
261 		"aaci", &mmc_data),
262 	OF_DEV_AUXDATA("arm,primecell", INTCP_PA_CLCD_BASE,
263 		"clcd", &clcd_data),
264 	OF_DEV_AUXDATA("cfi-flash", INTCP_PA_FLASH_BASE,
265 		"physmap-flash", &intcp_flash_data),
266 	{ /* sentinel */ },
267 };
268 
269 static const struct of_device_id intcp_syscon_match[] = {
270 	{ .compatible = "arm,integrator-cp-syscon"},
271 	{ },
272 };
273 
intcp_init_of(void)274 static void __init intcp_init_of(void)
275 {
276 	struct device_node *cpcon;
277 	struct device *parent;
278 	struct soc_device *soc_dev;
279 	struct soc_device_attribute *soc_dev_attr;
280 	u32 intcp_sc_id;
281 
282 	cpcon = of_find_matching_node(NULL, intcp_syscon_match);
283 	if (!cpcon)
284 		return;
285 
286 	intcp_con_base = of_iomap(cpcon, 0);
287 	if (!intcp_con_base)
288 		return;
289 
290 	of_platform_populate(NULL, of_default_bus_match_table,
291 			     intcp_auxdata_lookup, NULL);
292 
293 	intcp_sc_id = readl(intcp_con_base);
294 
295 	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
296 	if (!soc_dev_attr)
297 		return;
298 
299 	soc_dev_attr->soc_id = "XCV";
300 	soc_dev_attr->machine = "Integrator/CP";
301 	soc_dev_attr->family = "Integrator";
302 	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
303 					   'A' + (intcp_sc_id & 0x0f));
304 
305 	soc_dev = soc_device_register(soc_dev_attr);
306 	if (IS_ERR(soc_dev)) {
307 		kfree(soc_dev_attr->revision);
308 		kfree(soc_dev_attr);
309 		return;
310 	}
311 
312 	parent = soc_device_to_device(soc_dev);
313 	integrator_init_sysfs(parent, intcp_sc_id);
314 }
315 
316 static const char * intcp_dt_board_compat[] = {
317 	"arm,integrator-cp",
318 	NULL,
319 };
320 
321 DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
322 	.reserve	= integrator_reserve,
323 	.map_io		= intcp_map_io,
324 	.init_early	= intcp_init_early,
325 	.init_irq	= intcp_init_irq_of,
326 	.init_machine	= intcp_init_of,
327 	.restart	= integrator_restart,
328 	.dt_compat      = intcp_dt_board_compat,
329 MACHINE_END
330