linux/arch/arm/mach-omap2/board-h4.c

391 lines
9.6 KiB
C
Raw Normal View History

/*
* linux/arch/arm/mach-omap2/board-h4.c
*
* Copyright (C) 2005 Nokia Corporation
* Author: Paul Mundt <paul.mundt@nokia.com>
*
* Modified from mach-omap/omap1/board-generic.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
#include <linux/input.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/input/matrix_keypad.h>
#include <linux/mfd/menelaus.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
ARM: OMAP: Move plat-omap/dma-omap.h to include/linux/omap-dma.h Based on earlier discussions[1] we attempted to find a suitable location for the omap DMA header in commit 2b6c4e73 (ARM: OMAP: DMA: Move plat/dma.h to plat-omap/dma-omap.h) until the conversion to dmaengine is complete. Unfortunately that was before I was able to try to test compile of the ARM multiplatform builds for omap2+, and the end result was not very good. So I'm creating yet another all over the place patch to cut the last dependency for building omap2+ for ARM multiplatform. After this, we have finally removed the driver dependencies to the arch/arm code, except for few drivers that are being worked on. The other option was to make the <plat-omap/dma-omap.h> path to work, but we'd have to add some new header directory to for multiplatform builds. Or we would have to manually include arch/arm/plat-omap/include again from arch/arm/Makefile for omap2+. Neither of these alternatives sound appealing as they will likely lead addition of various other headers exposed to the drivers, which we want to avoid for the multiplatform kernels. Since we already have a minimal include/linux/omap-dma.h, let's just use that instead and add a note to it to not use the custom omap DMA functions any longer where possible. Note that converting omap DMA to dmaengine depends on dmaengine supporting automatically incrementing the FIFO address at the device end, and converting all the remaining legacy drivers. So it's going to be few more merge windows. [1] https://patchwork.kernel.org/patch/1519591/# cc: Russell King <linux@arm.linux.org.uk> cc: Kevin Hilman <khilman@ti.com> cc: "Benoît Cousson" <b-cousson@ti.com> cc: Herbert Xu <herbert@gondor.apana.org.au> cc: "David S. Miller" <davem@davemloft.net> cc: Vinod Koul <vinod.koul@intel.com> cc: Dan Williams <djbw@fb.com> cc: Mauro Carvalho Chehab <mchehab@infradead.org> cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de> cc: David Woodhouse <dwmw2@infradead.org> cc: Kyungmin Park <kyungmin.park@samsung.com> cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> cc: Tomi Valkeinen <tomi.valkeinen@ti.com> cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> cc: Hans Verkuil <hans.verkuil@cisco.com> cc: Vaibhav Hiremath <hvaibhav@ti.com> cc: Lokesh Vutla <lokeshvutla@ti.com> cc: Rusty Russell <rusty@rustcorp.com.au> cc: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> cc: Afzal Mohammed <afzal@ti.com> cc: linux-crypto@vger.kernel.org cc: linux-media@vger.kernel.org cc: linux-mtd@lists.infradead.org cc: linux-usb@vger.kernel.org cc: linux-fbdev@vger.kernel.org Acked-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
2012-12-01 00:41:50 +08:00
#include <linux/omap-dma.h>
#include <plat/debug-devices.h>
#include <video/omapdss.h>
#include <video/omap-panel-generic-dpi.h>
ARM: OMAP: Split plat/hardware.h, use local soc.h for omap2+ As the plat and mach includes need to disappear for single zImage work, we need to remove plat/hardware.h. Do this by splitting plat/hardware.h into omap1 and omap2+ specific files. The old plat/hardware.h already has omap1 only defines, so it gets moved to mach/hardware.h for omap1. For omap2+, we use the local soc.h that for now just includes the related SoC headers to keep this patch more readable. Note that the local soc.h still includes plat/cpu.h that can be dealt with in later patches. Let's also include plat/serial.h from common.h for all the board-*.c files. This allows making the include files local later on without patching these files again. Note that only minimal changes are done in this patch for the drivers/watchdog/omap_wdt.c driver to keep things compiling. Further patches are needed to eventually remove cpu_is_omap usage in the drivers. Also only minimal changes are done to sound/soc/omap/* to remove the unneeded includes and to define OMAP44XX_MCPDM_L3_BASE locally so there's no need to include omap44xx.h. While at it, also sort some of the includes in the standard way. Cc: linux-watchdog@vger.kernel.org Cc: alsa-devel@alsa-project.org Cc: Peter Ujfalusi <peter.ujfalusi@ti.com> Cc: Jarkko Nikula <jarkko.nikula@bitmer.com> Cc: Liam Girdwood <lrg@ti.com> Acked-by: Wim Van Sebroeck <wim@iguana.be> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
2012-09-01 01:59:07 +08:00
#include "common.h"
#include "mux.h"
#include "control.h"
#include "gpmc.h"
#define H4_FLASH_CS 0
#define H4_SMC91X_CS 1
#define H4_ETHR_GPIO_IRQ 92
#if defined(CONFIG_KEYBOARD_MATRIX) || defined(CONFIG_KEYBOARD_MATRIX_MODULE)
static const uint32_t board_matrix_keys[] = {
KEY(0, 0, KEY_LEFT),
KEY(1, 0, KEY_RIGHT),
KEY(2, 0, KEY_A),
KEY(3, 0, KEY_B),
KEY(4, 0, KEY_C),
KEY(0, 1, KEY_DOWN),
KEY(1, 1, KEY_UP),
KEY(2, 1, KEY_E),
KEY(3, 1, KEY_F),
KEY(4, 1, KEY_G),
KEY(0, 2, KEY_ENTER),
KEY(1, 2, KEY_I),
KEY(2, 2, KEY_J),
KEY(3, 2, KEY_K),
KEY(4, 2, KEY_3),
KEY(0, 3, KEY_M),
KEY(1, 3, KEY_N),
KEY(2, 3, KEY_O),
KEY(3, 3, KEY_P),
KEY(4, 3, KEY_Q),
KEY(0, 4, KEY_R),
KEY(1, 4, KEY_4),
KEY(2, 4, KEY_T),
KEY(3, 4, KEY_U),
KEY(4, 4, KEY_ENTER),
KEY(0, 5, KEY_V),
KEY(1, 5, KEY_W),
KEY(2, 5, KEY_L),
KEY(3, 5, KEY_S),
KEY(4, 5, KEY_ENTER),
};
static const struct matrix_keymap_data board_keymap_data = {
.keymap = board_matrix_keys,
.keymap_size = ARRAY_SIZE(board_matrix_keys),
};
static unsigned int board_keypad_row_gpios[] = {
88, 89, 124, 11, 6, 96
};
static unsigned int board_keypad_col_gpios[] = {
90, 91, 100, 36, 12, 97, 98
};
static struct matrix_keypad_platform_data board_keypad_platform_data = {
.keymap_data = &board_keymap_data,
.row_gpios = board_keypad_row_gpios,
.num_row_gpios = ARRAY_SIZE(board_keypad_row_gpios),
.col_gpios = board_keypad_col_gpios,
.num_col_gpios = ARRAY_SIZE(board_keypad_col_gpios),
.active_low = 1,
.debounce_ms = 20,
.col_scan_delay_us = 5,
};
static struct platform_device board_keyboard = {
.name = "matrix-keypad",
.id = -1,
.dev = {
.platform_data = &board_keypad_platform_data,
},
};
static void __init board_mkp_init(void)
{
omap_mux_init_gpio(88, OMAP_PULL_ENA | OMAP_PULL_UP);
omap_mux_init_gpio(89, OMAP_PULL_ENA | OMAP_PULL_UP);
omap_mux_init_gpio(124, OMAP_PULL_ENA | OMAP_PULL_UP);
omap_mux_init_signal("mcbsp2_dr.gpio_11", OMAP_PULL_ENA | OMAP_PULL_UP);
if (omap_has_menelaus()) {
omap_mux_init_signal("sdrc_a14.gpio0",
OMAP_PULL_ENA | OMAP_PULL_UP);
omap_mux_init_signal("vlynq_rx0.gpio_15", 0);
omap_mux_init_signal("gpio_98", 0);
board_keypad_row_gpios[5] = 0;
board_keypad_col_gpios[2] = 15;
board_keypad_col_gpios[6] = 18;
} else {
omap_mux_init_signal("gpio_96", OMAP_PULL_ENA | OMAP_PULL_UP);
omap_mux_init_signal("gpio_100", 0);
omap_mux_init_signal("gpio_98", 0);
}
omap_mux_init_signal("gpio_90", 0);
omap_mux_init_signal("gpio_91", 0);
omap_mux_init_signal("gpio_36", 0);
omap_mux_init_signal("mcbsp2_clkx.gpio_12", 0);
omap_mux_init_signal("gpio_97", 0);
platform_device_register(&board_keyboard);
}
#else
static inline void board_mkp_init(void)
{
}
#endif
static struct mtd_partition h4_partitions[] = {
/* bootloader (U-Boot, etc) in first sector */
{
.name = "bootloader",
.offset = 0,
.size = SZ_128K,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
/* bootloader params in the next sector */
{
.name = "params",
.offset = MTDPART_OFS_APPEND,
.size = SZ_128K,
.mask_flags = 0,
},
/* kernel */
{
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = SZ_2M,
.mask_flags = 0
},
/* file system */
{
.name = "filesystem",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
.mask_flags = 0
}
};
static struct physmap_flash_data h4_flash_data = {
.width = 2,
.parts = h4_partitions,
.nr_parts = ARRAY_SIZE(h4_partitions),
};
static struct resource h4_flash_resource = {
.flags = IORESOURCE_MEM,
};
static struct platform_device h4_flash_device = {
.name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &h4_flash_data,
},
.num_resources = 1,
.resource = &h4_flash_resource,
};
static struct platform_device *h4_devices[] __initdata = {
&h4_flash_device,
};
static struct panel_generic_dpi_data h4_panel_data = {
.name = "h4",
};
static struct omap_dss_device h4_lcd_device = {
.name = "lcd",
.driver_name = "generic_dpi_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.phy.dpi.data_lines = 16,
.data = &h4_panel_data,
};
static struct omap_dss_device *h4_dss_devices[] = {
&h4_lcd_device,
};
static struct omap_dss_board_info h4_dss_data = {
.num_devices = ARRAY_SIZE(h4_dss_devices),
.devices = h4_dss_devices,
.default_device = &h4_lcd_device,
};
/* 2420 Sysboot setup (2430 is different) */
static u32 get_sysboot_value(void)
{
return (omap_ctrl_readl(OMAP24XX_CONTROL_STATUS) &
(OMAP2_SYSBOOT_5_MASK | OMAP2_SYSBOOT_4_MASK |
OMAP2_SYSBOOT_3_MASK | OMAP2_SYSBOOT_2_MASK |
OMAP2_SYSBOOT_1_MASK | OMAP2_SYSBOOT_0_MASK));
}
/* H4-2420's always used muxed mode, H4-2422's always use non-muxed
*
* Note: OMAP-GIT doesn't correctly do is_cpu_omap2422 and is_cpu_omap2423
* correctly. The macro needs to look at production_id not just hawkeye.
*/
static u32 is_gpmc_muxed(void)
{
u32 mux;
mux = get_sysboot_value();
if ((mux & 0xF) == 0xd)
return 1; /* NAND config (could be either) */
if (mux & 0x2) /* if mux'ed */
return 1;
else
return 0;
}
static inline void __init h4_init_debug(void)
{
int eth_cs;
unsigned long cs_mem_base;
unsigned int muxed, rate;
struct clk *gpmc_fck;
eth_cs = H4_SMC91X_CS;
gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
if (IS_ERR(gpmc_fck)) {
WARN_ON(1);
return;
}
ARM: omap: clk: add clk_prepare and clk_unprepare As part of Common Clk Framework (CCF) the clk_enable() operation was split into a clk_prepare() which could sleep, and a clk_enable() which should never sleep. Similarly the clk_disable() was split into clk_disable() and clk_unprepare(). This was needed to handle complex cases where in a clk gate/ungate would require a slow and a fast part to be implemented. None of the clocks below seem to be in the 'complex' clocks category and are just simple clocks which are enabled/disabled through simple register writes. Most of the instances also seem to be called in non-atomic context which means its safe to move all of those from using a clk_enable() to clk_prepare_enable() and clk_disable() to clk_disable_unprepare(). For some others, mainly the ones handled through the hwmod framework there is a possibility that they get called in either an atomic or a non-atomic context. The way these get handled below work only as long as clk_prepare is implemented as a no-op (which is the case today) since this gets called very early at boot while most subsystems are unavailable. Hence these are marked with a *HACK* comment, which says we need to re-visit these once we start doing something meaningful with clk_prepare/clk_unprepare like doing voltage scaling or something that involves i2c. This is in preparation of OMAP moving to CCF. Based on initial changes from Mike Turquette. Signed-off-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
2012-09-22 16:24:16 +08:00
clk_prepare_enable(gpmc_fck);
rate = clk_get_rate(gpmc_fck);
ARM: omap: clk: add clk_prepare and clk_unprepare As part of Common Clk Framework (CCF) the clk_enable() operation was split into a clk_prepare() which could sleep, and a clk_enable() which should never sleep. Similarly the clk_disable() was split into clk_disable() and clk_unprepare(). This was needed to handle complex cases where in a clk gate/ungate would require a slow and a fast part to be implemented. None of the clocks below seem to be in the 'complex' clocks category and are just simple clocks which are enabled/disabled through simple register writes. Most of the instances also seem to be called in non-atomic context which means its safe to move all of those from using a clk_enable() to clk_prepare_enable() and clk_disable() to clk_disable_unprepare(). For some others, mainly the ones handled through the hwmod framework there is a possibility that they get called in either an atomic or a non-atomic context. The way these get handled below work only as long as clk_prepare is implemented as a no-op (which is the case today) since this gets called very early at boot while most subsystems are unavailable. Hence these are marked with a *HACK* comment, which says we need to re-visit these once we start doing something meaningful with clk_prepare/clk_unprepare like doing voltage scaling or something that involves i2c. This is in preparation of OMAP moving to CCF. Based on initial changes from Mike Turquette. Signed-off-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
2012-09-22 16:24:16 +08:00
clk_disable_unprepare(gpmc_fck);
clk_put(gpmc_fck);
if (is_gpmc_muxed())
muxed = 0x200;
else
muxed = 0;
/* Make sure CS1 timings are correct */
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1,
0x00011000 | muxed);
if (rate >= 160000000) {
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
} else if (rate >= 130000000) {
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
} else {/* rate = 100000000 */
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
}
if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
goto out;
}
udelay(100);
omap_mux_init_gpio(92, 0);
if (debug_card_init(cs_mem_base, H4_ETHR_GPIO_IRQ) < 0)
gpmc_cs_free(eth_cs);
out:
ARM: omap: clk: add clk_prepare and clk_unprepare As part of Common Clk Framework (CCF) the clk_enable() operation was split into a clk_prepare() which could sleep, and a clk_enable() which should never sleep. Similarly the clk_disable() was split into clk_disable() and clk_unprepare(). This was needed to handle complex cases where in a clk gate/ungate would require a slow and a fast part to be implemented. None of the clocks below seem to be in the 'complex' clocks category and are just simple clocks which are enabled/disabled through simple register writes. Most of the instances also seem to be called in non-atomic context which means its safe to move all of those from using a clk_enable() to clk_prepare_enable() and clk_disable() to clk_disable_unprepare(). For some others, mainly the ones handled through the hwmod framework there is a possibility that they get called in either an atomic or a non-atomic context. The way these get handled below work only as long as clk_prepare is implemented as a no-op (which is the case today) since this gets called very early at boot while most subsystems are unavailable. Hence these are marked with a *HACK* comment, which says we need to re-visit these once we start doing something meaningful with clk_prepare/clk_unprepare like doing voltage scaling or something that involves i2c. This is in preparation of OMAP moving to CCF. Based on initial changes from Mike Turquette. Signed-off-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
2012-09-22 16:24:16 +08:00
clk_disable_unprepare(gpmc_fck);
clk_put(gpmc_fck);
}
static void __init h4_init_flash(void)
{
unsigned long base;
if (gpmc_cs_request(H4_FLASH_CS, SZ_64M, &base) < 0) {
printk("Can't request GPMC CS for flash\n");
return;
}
h4_flash_resource.start = base;
h4_flash_resource.end = base + SZ_64M - 1;
}
static struct at24_platform_data m24c01 = {
.byte_len = SZ_1K / 8,
.page_size = 16,
};
static struct i2c_board_info __initdata h4_i2c_board_info[] = {
{
I2C_BOARD_INFO("isp1301_omap", 0x2d),
},
{ /* EEPROM on mainboard */
I2C_BOARD_INFO("24c01", 0x52),
.platform_data = &m24c01,
},
{ /* EEPROM on cpu card */
I2C_BOARD_INFO("24c01", 0x57),
.platform_data = &m24c01,
},
};
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#endif
static void __init omap_h4_init(void)
{
omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAF);
/*
* Make sure the serial ports are muxed on at this point.
* You have to mux them off in device drivers later on
* if not needed.
*/
board_mkp_init();
h4_i2c_board_info[0].irq = gpio_to_irq(125);
i2c_register_board_info(1, h4_i2c_board_info,
ARRAY_SIZE(h4_i2c_board_info));
platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
omap_serial_init();
omap_sdrc_init(NULL, NULL);
h4_init_flash();
omap_display_init(&h4_dss_data);
}
MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
.atag_offset = 0x100,
.reserve = omap_reserve,
.map_io = omap242x_map_io,
.init_early = omap2420_init_early,
.init_irq = omap2_init_irq,
.handle_irq = omap2_intc_handle_irq,
.init_machine = omap_h4_init,
.init_late = omap2420_init_late,
.timer = &omap2_timer,
.restart = omap2xxx_restart,
MACHINE_END