• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/mach-mx3/
1/*
2 *  Copyright (C) 2009 Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/types.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/memory.h>
19#include <linux/platform_device.h>
20#include <linux/mtd/physmap.h>
21#include <linux/mtd/nand.h>
22#include <linux/gpio.h>
23
24#include <mach/hardware.h>
25#include <mach/irqs.h>
26#include <asm/mach-types.h>
27#include <asm/mach/arch.h>
28#include <asm/mach/time.h>
29#include <asm/mach/map.h>
30#include <mach/common.h>
31#include <asm/page.h>
32#include <asm/setup.h>
33#include <mach/iomux-mx3.h>
34
35#include "devices-imx31.h"
36#include "devices.h"
37
38/* FPGA defines */
39#define QONG_FPGA_VERSION(major, minor, rev)	\
40	(((major & 0xF) << 12) | ((minor & 0xF) << 8) | (rev & 0xFF))
41
42#define QONG_FPGA_BASEADDR 		MX31_CS1_BASE_ADDR
43#define QONG_FPGA_PERIPH_SIZE 		(1 << 24)
44
45#define QONG_FPGA_CTRL_BASEADDR		QONG_FPGA_BASEADDR
46#define QONG_FPGA_CTRL_SIZE 		0x10
47/* FPGA control registers */
48#define QONG_FPGA_CTRL_VERSION		0x00
49
50#define QONG_DNET_ID		1
51#define QONG_DNET_BASEADDR	\
52	(QONG_FPGA_BASEADDR + QONG_DNET_ID * QONG_FPGA_PERIPH_SIZE)
53#define QONG_DNET_SIZE 		0x00001000
54
55#define QONG_FPGA_IRQ		IOMUX_TO_IRQ(MX31_PIN_DTR_DCE1)
56
57/*
58 * This file contains the board-specific initialization routines.
59 */
60
61static const struct imxuart_platform_data uart_pdata __initconst = {
62	.flags = IMXUART_HAVE_RTSCTS,
63};
64
65static int uart_pins[] = {
66	MX31_PIN_CTS1__CTS1,
67	MX31_PIN_RTS1__RTS1,
68	MX31_PIN_TXD1__TXD1,
69	MX31_PIN_RXD1__RXD1
70};
71
72static inline void __init mxc_init_imx_uart(void)
73{
74	mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins),
75			"uart-0");
76	imx31_add_imx_uart0(&uart_pdata);
77}
78
79static struct resource dnet_resources[] = {
80	{
81		.name	= "dnet-memory",
82		.start	= QONG_DNET_BASEADDR,
83		.end	= QONG_DNET_BASEADDR + QONG_DNET_SIZE - 1,
84		.flags	= IORESOURCE_MEM,
85	}, {
86		.start	= QONG_FPGA_IRQ,
87		.end	= QONG_FPGA_IRQ,
88		.flags	= IORESOURCE_IRQ,
89	},
90};
91
92static struct platform_device dnet_device = {
93	.name			= "dnet",
94	.id			= -1,
95	.num_resources		= ARRAY_SIZE(dnet_resources),
96	.resource		= dnet_resources,
97};
98
99static int __init qong_init_dnet(void)
100{
101	int ret;
102
103	ret = platform_device_register(&dnet_device);
104	return ret;
105}
106
107/* MTD NOR flash */
108
109static struct physmap_flash_data qong_flash_data = {
110	.width = 2,
111};
112
113static struct resource qong_flash_resource = {
114	.start = MX31_CS0_BASE_ADDR,
115	.end = MX31_CS0_BASE_ADDR + SZ_128M - 1,
116	.flags = IORESOURCE_MEM,
117};
118
119static struct platform_device qong_nor_mtd_device = {
120	.name = "physmap-flash",
121	.id = 0,
122	.dev = {
123		.platform_data = &qong_flash_data,
124		},
125	.resource = &qong_flash_resource,
126	.num_resources = 1,
127};
128
129static void qong_init_nor_mtd(void)
130{
131	(void)platform_device_register(&qong_nor_mtd_device);
132}
133
134/*
135 * Hardware specific access to control-lines
136 */
137static void qong_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
138{
139	struct nand_chip *nand_chip = mtd->priv;
140
141	if (cmd == NAND_CMD_NONE)
142		return;
143
144	if (ctrl & NAND_CLE)
145		writeb(cmd, nand_chip->IO_ADDR_W + (1 << 24));
146	else
147		writeb(cmd, nand_chip->IO_ADDR_W + (1 << 23));
148}
149
150/*
151 * Read the Device Ready pin.
152 */
153static int qong_nand_device_ready(struct mtd_info *mtd)
154{
155	return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_NFRB));
156}
157
158static void qong_nand_select_chip(struct mtd_info *mtd, int chip)
159{
160	if (chip >= 0)
161		gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 0);
162	else
163		gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 1);
164}
165
166static struct platform_nand_data qong_nand_data = {
167	.chip = {
168		.nr_chips		= 1,
169		.chip_delay		= 20,
170		.options		= 0,
171	},
172	.ctrl = {
173		.cmd_ctrl 		= qong_nand_cmd_ctrl,
174		.dev_ready		= qong_nand_device_ready,
175		.select_chip		= qong_nand_select_chip,
176	}
177};
178
179static struct resource qong_nand_resource = {
180	.start  	= MX31_CS3_BASE_ADDR,
181	.end    	= MX31_CS3_BASE_ADDR + SZ_32M - 1,
182	.flags		= IORESOURCE_MEM,
183};
184
185static struct platform_device qong_nand_device = {
186	.name		= "gen_nand",
187	.id		= -1,
188	.dev		= {
189		.platform_data = &qong_nand_data,
190	},
191	.num_resources	= 1,
192	.resource	= &qong_nand_resource,
193};
194
195static void __init qong_init_nand_mtd(void)
196{
197	/* init CS */
198	mx31_setup_weimcs(3, 0x00004f00, 0x20013b31, 0x00020800);
199	mxc_iomux_set_gpr(MUX_SDCTL_CSD1_SEL, true);
200
201	/* enable pin */
202	mxc_iomux_mode(IOMUX_MODE(MX31_PIN_NFCE_B, IOMUX_CONFIG_GPIO));
203	if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), "nand_enable"))
204		gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 0);
205
206	/* ready/busy pin */
207	mxc_iomux_mode(IOMUX_MODE(MX31_PIN_NFRB, IOMUX_CONFIG_GPIO));
208	if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_NFRB), "nand_rdy"))
209		gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_NFRB));
210
211	/* write protect pin */
212	mxc_iomux_mode(IOMUX_MODE(MX31_PIN_NFWP_B, IOMUX_CONFIG_GPIO));
213	if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_NFWP_B), "nand_wp"))
214		gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_NFWP_B));
215
216	platform_device_register(&qong_nand_device);
217}
218
219static void __init qong_init_fpga(void)
220{
221	void __iomem *regs;
222	u32 fpga_ver;
223
224	regs = ioremap(QONG_FPGA_CTRL_BASEADDR, QONG_FPGA_CTRL_SIZE);
225	if (!regs) {
226		printk(KERN_ERR "%s: failed to map registers, aborting.\n",
227				__func__);
228		return;
229	}
230
231	fpga_ver = readl(regs + QONG_FPGA_CTRL_VERSION);
232	iounmap(regs);
233	printk(KERN_INFO "Qong FPGA version %d.%d.%d\n",
234			(fpga_ver & 0xF000) >> 12,
235			(fpga_ver & 0x0F00) >> 8, fpga_ver & 0x00FF);
236	if (fpga_ver < QONG_FPGA_VERSION(0, 8, 7)) {
237		printk(KERN_ERR "qong: Unexpected FPGA version, FPGA-based "
238				"devices won't be registered!\n");
239		return;
240	}
241
242	/* register FPGA-based devices */
243	qong_init_nand_mtd();
244	qong_init_dnet();
245}
246
247/*
248 * Board specific initialization.
249 */
250static void __init mxc_board_init(void)
251{
252	mxc_init_imx_uart();
253	qong_init_nor_mtd();
254	qong_init_fpga();
255}
256
257static void __init qong_timer_init(void)
258{
259	mx31_clocks_init(26000000);
260}
261
262static struct sys_timer qong_timer = {
263	.init	= qong_timer_init,
264};
265
266/*
267 * The following uses standard kernel macros defined in arch.h in order to
268 * initialize __mach_desc_QONG data structure.
269 */
270
271MACHINE_START(QONG, "Dave/DENX QongEVB-LITE")
272	/* Maintainer: DENX Software Engineering GmbH */
273	.phys_io        = MX31_AIPS1_BASE_ADDR,
274	.io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
275	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
276	.map_io         = mx31_map_io,
277	.init_irq       = mx31_init_irq,
278	.init_machine   = mxc_board_init,
279	.timer          = &qong_timer,
280MACHINE_END
281