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