xref: /OK3568_Linux_fs/kernel/arch/mips/rb532/devices.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  RouterBoard 500 Platform devices
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
6*4882a593Smuzhiyun  *  Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/export.h>
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/ctype.h>
12*4882a593Smuzhiyun #include <linux/string.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/mtd/platnand.h>
15*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
16*4882a593Smuzhiyun #include <linux/gpio.h>
17*4882a593Smuzhiyun #include <linux/gpio/machine.h>
18*4882a593Smuzhiyun #include <linux/gpio_keys.h>
19*4882a593Smuzhiyun #include <linux/input.h>
20*4882a593Smuzhiyun #include <linux/serial_8250.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <asm/bootinfo.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include <asm/mach-rc32434/rc32434.h>
25*4882a593Smuzhiyun #include <asm/mach-rc32434/dma.h>
26*4882a593Smuzhiyun #include <asm/mach-rc32434/dma_v.h>
27*4882a593Smuzhiyun #include <asm/mach-rc32434/eth.h>
28*4882a593Smuzhiyun #include <asm/mach-rc32434/rb.h>
29*4882a593Smuzhiyun #include <asm/mach-rc32434/integ.h>
30*4882a593Smuzhiyun #include <asm/mach-rc32434/gpio.h>
31*4882a593Smuzhiyun #include <asm/mach-rc32434/irq.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define ETH0_RX_DMA_ADDR  (DMA0_BASE_ADDR + 0 * DMA_CHAN_OFFSET)
34*4882a593Smuzhiyun #define ETH0_TX_DMA_ADDR  (DMA0_BASE_ADDR + 1 * DMA_CHAN_OFFSET)
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun extern unsigned int idt_cpu_freq;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun static struct mpmc_device dev3;
39*4882a593Smuzhiyun 
set_latch_u5(unsigned char or_mask,unsigned char nand_mask)40*4882a593Smuzhiyun void set_latch_u5(unsigned char or_mask, unsigned char nand_mask)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	unsigned long flags;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	spin_lock_irqsave(&dev3.lock, flags);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	dev3.state = (dev3.state | or_mask) & ~nand_mask;
47*4882a593Smuzhiyun 	writeb(dev3.state, dev3.base);
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev3.lock, flags);
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun EXPORT_SYMBOL(set_latch_u5);
52*4882a593Smuzhiyun 
get_latch_u5(void)53*4882a593Smuzhiyun unsigned char get_latch_u5(void)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	return dev3.state;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun EXPORT_SYMBOL(get_latch_u5);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun static struct resource korina_dev0_res[] = {
60*4882a593Smuzhiyun 	{
61*4882a593Smuzhiyun 		.name = "korina_regs",
62*4882a593Smuzhiyun 		.start = ETH0_BASE_ADDR,
63*4882a593Smuzhiyun 		.end = ETH0_BASE_ADDR + sizeof(struct eth_regs),
64*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM,
65*4882a593Smuzhiyun 	 }, {
66*4882a593Smuzhiyun 		.name = "korina_rx",
67*4882a593Smuzhiyun 		.start = ETH0_DMA_RX_IRQ,
68*4882a593Smuzhiyun 		.end = ETH0_DMA_RX_IRQ,
69*4882a593Smuzhiyun 		.flags = IORESOURCE_IRQ
70*4882a593Smuzhiyun 	}, {
71*4882a593Smuzhiyun 		.name = "korina_tx",
72*4882a593Smuzhiyun 		.start = ETH0_DMA_TX_IRQ,
73*4882a593Smuzhiyun 		.end = ETH0_DMA_TX_IRQ,
74*4882a593Smuzhiyun 		.flags = IORESOURCE_IRQ
75*4882a593Smuzhiyun 	}, {
76*4882a593Smuzhiyun 		.name = "korina_ovr",
77*4882a593Smuzhiyun 		.start = ETH0_RX_OVR_IRQ,
78*4882a593Smuzhiyun 		.end = ETH0_RX_OVR_IRQ,
79*4882a593Smuzhiyun 		.flags = IORESOURCE_IRQ
80*4882a593Smuzhiyun 	}, {
81*4882a593Smuzhiyun 		.name = "korina_und",
82*4882a593Smuzhiyun 		.start = ETH0_TX_UND_IRQ,
83*4882a593Smuzhiyun 		.end = ETH0_TX_UND_IRQ,
84*4882a593Smuzhiyun 		.flags = IORESOURCE_IRQ
85*4882a593Smuzhiyun 	}, {
86*4882a593Smuzhiyun 		.name = "korina_dma_rx",
87*4882a593Smuzhiyun 		.start = ETH0_RX_DMA_ADDR,
88*4882a593Smuzhiyun 		.end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
89*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM,
90*4882a593Smuzhiyun 	 }, {
91*4882a593Smuzhiyun 		.name = "korina_dma_tx",
92*4882a593Smuzhiyun 		.start = ETH0_TX_DMA_ADDR,
93*4882a593Smuzhiyun 		.end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
94*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM,
95*4882a593Smuzhiyun 	 }
96*4882a593Smuzhiyun };
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun static struct korina_device korina_dev0_data = {
99*4882a593Smuzhiyun 	.name = "korina0",
100*4882a593Smuzhiyun 	.mac = {0xde, 0xca, 0xff, 0xc0, 0xff, 0xee}
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun static struct platform_device korina_dev0 = {
104*4882a593Smuzhiyun 	.id = -1,
105*4882a593Smuzhiyun 	.name = "korina",
106*4882a593Smuzhiyun 	.resource = korina_dev0_res,
107*4882a593Smuzhiyun 	.num_resources = ARRAY_SIZE(korina_dev0_res),
108*4882a593Smuzhiyun };
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun static struct resource cf_slot0_res[] = {
111*4882a593Smuzhiyun 	{
112*4882a593Smuzhiyun 		.name = "cf_membase",
113*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM
114*4882a593Smuzhiyun 	}, {
115*4882a593Smuzhiyun 		.name = "cf_irq",
116*4882a593Smuzhiyun 		.start = (8 + 4 * 32 + CF_GPIO_NUM),	/* 149 */
117*4882a593Smuzhiyun 		.end = (8 + 4 * 32 + CF_GPIO_NUM),
118*4882a593Smuzhiyun 		.flags = IORESOURCE_IRQ
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun static struct gpiod_lookup_table cf_slot0_gpio_table = {
123*4882a593Smuzhiyun 	.dev_id = "pata-rb532-cf",
124*4882a593Smuzhiyun 	.table = {
125*4882a593Smuzhiyun 		GPIO_LOOKUP("gpio0", CF_GPIO_NUM,
126*4882a593Smuzhiyun 			    NULL, GPIO_ACTIVE_HIGH),
127*4882a593Smuzhiyun 		{ },
128*4882a593Smuzhiyun 	},
129*4882a593Smuzhiyun };
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun static struct platform_device cf_slot0 = {
132*4882a593Smuzhiyun 	.id = -1,
133*4882a593Smuzhiyun 	.name = "pata-rb532-cf",
134*4882a593Smuzhiyun 	.resource = cf_slot0_res,
135*4882a593Smuzhiyun 	.num_resources = ARRAY_SIZE(cf_slot0_res),
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun /* Resources and device for NAND */
rb532_dev_ready(struct nand_chip * chip)139*4882a593Smuzhiyun static int rb532_dev_ready(struct nand_chip *chip)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	return gpio_get_value(GPIO_RDY);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
rb532_cmd_ctrl(struct nand_chip * chip,int cmd,unsigned int ctrl)144*4882a593Smuzhiyun static void rb532_cmd_ctrl(struct nand_chip *chip, int cmd, unsigned int ctrl)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	unsigned char orbits, nandbits;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (ctrl & NAND_CTRL_CHANGE) {
149*4882a593Smuzhiyun 		orbits = (ctrl & NAND_CLE) << 1;
150*4882a593Smuzhiyun 		orbits |= (ctrl & NAND_ALE) >> 1;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		nandbits = (~ctrl & NAND_CLE) << 1;
153*4882a593Smuzhiyun 		nandbits |= (~ctrl & NAND_ALE) >> 1;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		set_latch_u5(orbits, nandbits);
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 	if (cmd != NAND_CMD_NONE)
158*4882a593Smuzhiyun 		writeb(cmd, chip->legacy.IO_ADDR_W);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun static struct resource nand_slot0_res[] = {
162*4882a593Smuzhiyun 	[0] = {
163*4882a593Smuzhiyun 		.name = "nand_membase",
164*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun };
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun static struct platform_nand_data rb532_nand_data = {
169*4882a593Smuzhiyun 	.ctrl.dev_ready = rb532_dev_ready,
170*4882a593Smuzhiyun 	.ctrl.cmd_ctrl	= rb532_cmd_ctrl,
171*4882a593Smuzhiyun };
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun static struct platform_device nand_slot0 = {
174*4882a593Smuzhiyun 	.name = "gen_nand",
175*4882a593Smuzhiyun 	.id = -1,
176*4882a593Smuzhiyun 	.resource = nand_slot0_res,
177*4882a593Smuzhiyun 	.num_resources = ARRAY_SIZE(nand_slot0_res),
178*4882a593Smuzhiyun 	.dev.platform_data = &rb532_nand_data,
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun static struct mtd_partition rb532_partition_info[] = {
182*4882a593Smuzhiyun 	{
183*4882a593Smuzhiyun 		.name = "Routerboard NAND boot",
184*4882a593Smuzhiyun 		.offset = 0,
185*4882a593Smuzhiyun 		.size = 4 * 1024 * 1024,
186*4882a593Smuzhiyun 	}, {
187*4882a593Smuzhiyun 		.name = "rootfs",
188*4882a593Smuzhiyun 		.offset = MTDPART_OFS_NXTBLK,
189*4882a593Smuzhiyun 		.size = MTDPART_SIZ_FULL,
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun static struct platform_device rb532_led = {
194*4882a593Smuzhiyun 	.name = "rb532-led",
195*4882a593Smuzhiyun 	.id = -1,
196*4882a593Smuzhiyun };
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun static struct platform_device rb532_button = {
199*4882a593Smuzhiyun 	.name	= "rb532-button",
200*4882a593Smuzhiyun 	.id	= -1,
201*4882a593Smuzhiyun };
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun static struct resource rb532_wdt_res[] = {
204*4882a593Smuzhiyun 	{
205*4882a593Smuzhiyun 		.name = "rb532_wdt_res",
206*4882a593Smuzhiyun 		.start = INTEG0_BASE_ADDR,
207*4882a593Smuzhiyun 		.end = INTEG0_BASE_ADDR + sizeof(struct integ),
208*4882a593Smuzhiyun 		.flags = IORESOURCE_MEM,
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun static struct platform_device rb532_wdt = {
213*4882a593Smuzhiyun 	.name		= "rc32434_wdt",
214*4882a593Smuzhiyun 	.id		= -1,
215*4882a593Smuzhiyun 	.resource	= rb532_wdt_res,
216*4882a593Smuzhiyun 	.num_resources	= ARRAY_SIZE(rb532_wdt_res),
217*4882a593Smuzhiyun };
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun static struct plat_serial8250_port rb532_uart_res[] = {
220*4882a593Smuzhiyun 	{
221*4882a593Smuzhiyun 		.type           = PORT_16550A,
222*4882a593Smuzhiyun 		.membase	= (char *)KSEG1ADDR(REGBASE + UART0BASE),
223*4882a593Smuzhiyun 		.irq		= UART0_IRQ,
224*4882a593Smuzhiyun 		.regshift	= 2,
225*4882a593Smuzhiyun 		.iotype		= UPIO_MEM,
226*4882a593Smuzhiyun 		.flags		= UPF_BOOT_AUTOCONF,
227*4882a593Smuzhiyun 	},
228*4882a593Smuzhiyun 	{
229*4882a593Smuzhiyun 		.flags		= 0,
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun };
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun static struct platform_device rb532_uart = {
234*4882a593Smuzhiyun 	.name		   = "serial8250",
235*4882a593Smuzhiyun 	.id		   = PLAT8250_DEV_PLATFORM,
236*4882a593Smuzhiyun 	.dev.platform_data = &rb532_uart_res,
237*4882a593Smuzhiyun };
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun static struct platform_device *rb532_devs[] = {
240*4882a593Smuzhiyun 	&korina_dev0,
241*4882a593Smuzhiyun 	&nand_slot0,
242*4882a593Smuzhiyun 	&cf_slot0,
243*4882a593Smuzhiyun 	&rb532_led,
244*4882a593Smuzhiyun 	&rb532_button,
245*4882a593Smuzhiyun 	&rb532_uart,
246*4882a593Smuzhiyun 	&rb532_wdt
247*4882a593Smuzhiyun };
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun /* NAND definitions */
250*4882a593Smuzhiyun #define NAND_CHIP_DELAY 25
251*4882a593Smuzhiyun 
rb532_nand_setup(void)252*4882a593Smuzhiyun static void __init rb532_nand_setup(void)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	switch (mips_machtype) {
255*4882a593Smuzhiyun 	case MACH_MIKROTIK_RB532A:
256*4882a593Smuzhiyun 		set_latch_u5(LO_FOFF | LO_CEX,
257*4882a593Smuzhiyun 				LO_ULED | LO_ALE | LO_CLE | LO_WPX);
258*4882a593Smuzhiyun 		break;
259*4882a593Smuzhiyun 	default:
260*4882a593Smuzhiyun 		set_latch_u5(LO_WPX | LO_FOFF | LO_CEX,
261*4882a593Smuzhiyun 				LO_ULED | LO_ALE | LO_CLE);
262*4882a593Smuzhiyun 		break;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	/* Setup NAND specific settings */
266*4882a593Smuzhiyun 	rb532_nand_data.chip.nr_chips = 1;
267*4882a593Smuzhiyun 	rb532_nand_data.chip.nr_partitions = ARRAY_SIZE(rb532_partition_info);
268*4882a593Smuzhiyun 	rb532_nand_data.chip.partitions = rb532_partition_info;
269*4882a593Smuzhiyun 	rb532_nand_data.chip.chip_delay = NAND_CHIP_DELAY;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 
plat_setup_devices(void)273*4882a593Smuzhiyun static int __init plat_setup_devices(void)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	/* Look for the CF card reader */
276*4882a593Smuzhiyun 	if (!readl(IDT434_REG_BASE + DEV1MASK))
277*4882a593Smuzhiyun 		rb532_devs[2] = NULL;	/* disable cf_slot0 at index 2 */
278*4882a593Smuzhiyun 	else {
279*4882a593Smuzhiyun 		cf_slot0_res[0].start =
280*4882a593Smuzhiyun 		    readl(IDT434_REG_BASE + DEV1BASE);
281*4882a593Smuzhiyun 		cf_slot0_res[0].end = cf_slot0_res[0].start + 0x1000;
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* Read the NAND resources from the device controller */
285*4882a593Smuzhiyun 	nand_slot0_res[0].start = readl(IDT434_REG_BASE + DEV2BASE);
286*4882a593Smuzhiyun 	nand_slot0_res[0].end = nand_slot0_res[0].start + 0x1000;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* Read and map device controller 3 */
289*4882a593Smuzhiyun 	dev3.base = ioremap(readl(IDT434_REG_BASE + DEV3BASE), 1);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	if (!dev3.base) {
292*4882a593Smuzhiyun 		printk(KERN_ERR "rb532: cannot remap device controller 3\n");
293*4882a593Smuzhiyun 		return -ENXIO;
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	/* Initialise the NAND device */
297*4882a593Smuzhiyun 	rb532_nand_setup();
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	/* set the uart clock to the current cpu frequency */
300*4882a593Smuzhiyun 	rb532_uart_res[0].uartclk = idt_cpu_freq;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	dev_set_drvdata(&korina_dev0.dev, &korina_dev0_data);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	gpiod_add_lookup_table(&cf_slot0_gpio_table);
305*4882a593Smuzhiyun 	return platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs));
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun #ifdef CONFIG_NET
309*4882a593Smuzhiyun 
setup_kmac(char * s)310*4882a593Smuzhiyun static int __init setup_kmac(char *s)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun 	printk(KERN_INFO "korina mac = %s\n", s);
313*4882a593Smuzhiyun 	if (!mac_pton(s, korina_dev0_data.mac))
314*4882a593Smuzhiyun 		printk(KERN_ERR "Invalid mac\n");
315*4882a593Smuzhiyun 	return 1;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun __setup("kmac=", setup_kmac);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun #endif /* CONFIG_NET */
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun arch_initcall(plat_setup_devices);
323