diff options
Diffstat (limited to 'arch/arm/mach-ux500')
54 files changed, 3540 insertions, 1261 deletions
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 2dd44a0b4615..203b986280f5 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -6,29 +6,32 @@ config UX500_SOC_COMMON select ARM_GIC select HAS_MTU select NOMADIK_GPIO + select ARM_ERRATA_753970 -config UX500_SOC_DB8500 - bool +menu "Ux500 SoC" config UX500_SOC_DB5500 - bool + bool "DB5500" + +config UX500_SOC_DB8500 + bool "DB8500" + +endmenu -choice - prompt "Ux500 target platform" - default MACH_U8500_MOP +menu "Ux500 target platform" -config MACH_U8500_MOP +config MACH_U8500 bool "U8500 Development platform" - select UX500_SOC_DB8500 + depends on UX500_SOC_DB8500 help Include support for the mop500 development platform. config MACH_U5500 bool "U5500 Development platform" - select UX500_SOC_DB5500 + depends on UX500_SOC_DB5500 help Include support for the U5500 development platform. -endchoice +endmenu config UX500_DEBUG_UART int "Ux500 UART to use for low-level debug" @@ -39,14 +42,14 @@ config UX500_DEBUG_UART config U5500_MODEM_IRQ bool "Modem IRQ support" - depends on MACH_U5500 + depends on UX500_SOC_DB5500 default y help Add support for handling IRQ:s from modem side config U5500_MBOX bool "Mailbox support" - depends on MACH_U5500 && U5500_MODEM_IRQ + depends on U5500_MODEM_IRQ default y help Add support for U5500 mailbox communication with modem side diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 9e27a84433cb..b549a8fb4231 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -2,14 +2,19 @@ # Makefile for the linux kernel, U8500 machine. # -obj-y := clock.o cpu.o devices.o -obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o +obj-y := clock.o cpu.o devices.o devices-common.o \ + id.o usb.o +obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o -obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-sdi.o -obj-$(CONFIG_MACH_U5500) += board-u5500.o +obj-$(CONFIG_MACH_U8500) += board-mop500.o board-mop500-sdi.o \ + board-mop500-regulators.o \ + board-mop500-uib.o board-mop500-stuib.o \ + board-mop500-u8500uib.o \ + board-mop500-pins.o +obj-$(CONFIG_MACH_U5500) += board-u5500.o board-u5500-sdi.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o -obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o -obj-$(CONFIG_U5500_MODEM_IRQ) += modem_irq.o -obj-$(CONFIG_U5500_MBOX) += mbox.o +obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o +obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c new file mode 100644 index 000000000000..fd4cf1ca5efd --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-pins.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> + +#include <asm/mach-types.h> +#include <plat/pincfg.h> +#include <mach/hardware.h> + +#include "pins-db8500.h" + +static pin_cfg_t mop500_pins_common[] = { + /* I2C */ + GPIO147_I2C0_SCL, + GPIO148_I2C0_SDA, + GPIO16_I2C1_SCL, + GPIO17_I2C1_SDA, + GPIO10_I2C2_SDA, + GPIO11_I2C2_SCL, + GPIO229_I2C3_SDA, + GPIO230_I2C3_SCL, + + /* MSP0 */ + GPIO12_MSP0_TXD, + GPIO13_MSP0_TFS, + GPIO14_MSP0_TCK, + GPIO15_MSP0_RXD, + + /* MSP2: HDMI */ + GPIO193_MSP2_TXD, + GPIO194_MSP2_TCK, + GPIO195_MSP2_TFS, + GPIO196_MSP2_RXD | PIN_OUTPUT_LOW, + + /* Touch screen INTERFACE */ + GPIO84_GPIO | PIN_INPUT_PULLUP, /* TOUCH_INT1 */ + + /* STMPE1601/tc35893 keypad IRQ */ + GPIO218_GPIO | PIN_INPUT_PULLUP, + + /* MMC0 (MicroSD card) */ + GPIO18_MC0_CMDDIR | PIN_OUTPUT_HIGH, + GPIO19_MC0_DAT0DIR | PIN_OUTPUT_HIGH, + GPIO20_MC0_DAT2DIR | PIN_OUTPUT_HIGH, + + GPIO22_MC0_FBCLK | PIN_INPUT_NOPULL, + GPIO23_MC0_CLK | PIN_OUTPUT_LOW, + GPIO24_MC0_CMD | PIN_INPUT_PULLUP, + GPIO25_MC0_DAT0 | PIN_INPUT_PULLUP, + GPIO26_MC0_DAT1 | PIN_INPUT_PULLUP, + GPIO27_MC0_DAT2 | PIN_INPUT_PULLUP, + GPIO28_MC0_DAT3 | PIN_INPUT_PULLUP, + + /* SDI1 (SDIO) */ + GPIO208_MC1_CLK | PIN_OUTPUT_LOW, + GPIO209_MC1_FBCLK | PIN_INPUT_NOPULL, + GPIO210_MC1_CMD | PIN_INPUT_PULLUP, + GPIO211_MC1_DAT0 | PIN_INPUT_PULLUP, + GPIO212_MC1_DAT1 | PIN_INPUT_PULLUP, + GPIO213_MC1_DAT2 | PIN_INPUT_PULLUP, + GPIO214_MC1_DAT3 | PIN_INPUT_PULLUP, + + /* MMC2 (On-board DATA INTERFACE eMMC) */ + GPIO128_MC2_CLK | PIN_OUTPUT_LOW, + GPIO129_MC2_CMD | PIN_INPUT_PULLUP, + GPIO130_MC2_FBCLK | PIN_INPUT_NOPULL, + GPIO131_MC2_DAT0 | PIN_INPUT_PULLUP, + GPIO132_MC2_DAT1 | PIN_INPUT_PULLUP, + GPIO133_MC2_DAT2 | PIN_INPUT_PULLUP, + GPIO134_MC2_DAT3 | PIN_INPUT_PULLUP, + GPIO135_MC2_DAT4 | PIN_INPUT_PULLUP, + GPIO136_MC2_DAT5 | PIN_INPUT_PULLUP, + GPIO137_MC2_DAT6 | PIN_INPUT_PULLUP, + GPIO138_MC2_DAT7 | PIN_INPUT_PULLUP, + + /* MMC4 (On-board STORAGE INTERFACE eMMC) */ + GPIO197_MC4_DAT3 | PIN_INPUT_PULLUP, + GPIO198_MC4_DAT2 | PIN_INPUT_PULLUP, + GPIO199_MC4_DAT1 | PIN_INPUT_PULLUP, + GPIO200_MC4_DAT0 | PIN_INPUT_PULLUP, + GPIO201_MC4_CMD | PIN_INPUT_PULLUP, + GPIO202_MC4_FBCLK | PIN_INPUT_NOPULL, + GPIO203_MC4_CLK | PIN_OUTPUT_LOW, + GPIO204_MC4_DAT7 | PIN_INPUT_PULLUP, + GPIO205_MC4_DAT6 | PIN_INPUT_PULLUP, + GPIO206_MC4_DAT5 | PIN_INPUT_PULLUP, + GPIO207_MC4_DAT4 | PIN_INPUT_PULLUP, + + /* SKE keypad */ + GPIO153_KP_I7, + GPIO154_KP_I6, + GPIO155_KP_I5, + GPIO156_KP_I4, + GPIO157_KP_O7, + GPIO158_KP_O6, + GPIO159_KP_O5, + GPIO160_KP_O4, + GPIO161_KP_I3, + GPIO162_KP_I2, + GPIO163_KP_I1, + GPIO164_KP_I0, + GPIO165_KP_O3, + GPIO166_KP_O2, + GPIO167_KP_O1, + GPIO168_KP_O0, + + /* UART */ + GPIO0_U0_CTSn | PIN_INPUT_PULLUP, + GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, + GPIO2_U0_RXD | PIN_INPUT_PULLUP, + GPIO3_U0_TXD | PIN_OUTPUT_HIGH, + + GPIO29_U2_RXD | PIN_INPUT_PULLUP, + GPIO30_U2_TXD | PIN_OUTPUT_HIGH, + GPIO31_U2_CTSn | PIN_INPUT_PULLUP, + GPIO32_U2_RTSn | PIN_OUTPUT_HIGH, + + /* Display & HDMI HW sync */ + GPIO68_LCD_VSI0 | PIN_INPUT_PULLUP, + GPIO69_LCD_VSI1 | PIN_INPUT_PULLUP, +}; + +static pin_cfg_t mop500_pins_default[] = { + /* SSP0 */ + GPIO143_SSP0_CLK, + GPIO144_SSP0_FRM, + GPIO145_SSP0_RXD | PIN_PULL_DOWN, + GPIO146_SSP0_TXD, + + + GPIO217_GPIO | PIN_INPUT_PULLUP, /* TC35892 IRQ */ + + /* SDI0 (MicroSD card) */ + GPIO21_MC0_DAT31DIR | PIN_OUTPUT_HIGH, + + /* UART */ + GPIO4_U1_RXD | PIN_INPUT_PULLUP, + GPIO5_U1_TXD | PIN_OUTPUT_HIGH, + GPIO6_U1_CTSn | PIN_INPUT_PULLUP, + GPIO7_U1_RTSn | PIN_OUTPUT_HIGH, +}; + +static pin_cfg_t mop500_pins_hrefv60[] = { + /* WLAN */ + GPIO4_GPIO | PIN_INPUT_PULLUP,/* WLAN_IRQ */ + GPIO85_GPIO | PIN_OUTPUT_LOW,/* WLAN_ENA */ + + /* XENON Flashgun INTERFACE */ + GPIO6_IP_GPIO0 | PIN_INPUT_PULLUP,/* XENON_FLASH_ID */ + GPIO7_IP_GPIO1 | PIN_INPUT_PULLUP,/* XENON_READY */ + GPIO170_GPIO | PIN_OUTPUT_LOW, /* XENON_CHARGE */ + + /* Assistant LED INTERFACE */ + GPIO21_GPIO | PIN_OUTPUT_LOW, /* XENON_EN1 */ + GPIO64_IP_GPIO4 | PIN_OUTPUT_LOW, /* XENON_EN2 */ + + /* Magnetometer */ + GPIO31_GPIO | PIN_INPUT_PULLUP, /* magnetometer_INT */ + GPIO32_GPIO | PIN_INPUT_PULLDOWN, /* Magnetometer DRDY */ + + /* Display Interface */ + GPIO65_GPIO | PIN_OUTPUT_LOW, /* DISP1 RST */ + GPIO66_GPIO | PIN_OUTPUT_LOW, /* DISP2 RST */ + + /* Touch screen INTERFACE */ + GPIO143_GPIO | PIN_OUTPUT_LOW,/*TOUCH_RST1 */ + + /* Touch screen INTERFACE 2 */ + GPIO67_GPIO | PIN_INPUT_PULLUP, /* TOUCH_INT2 */ + GPIO146_GPIO | PIN_OUTPUT_LOW,/*TOUCH_RST2 */ + + /* ETM_PTM_TRACE INTERFACE */ + GPIO70_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA23 */ + GPIO71_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA22 */ + GPIO72_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA21 */ + GPIO73_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA20 */ + GPIO74_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA19 */ + + /* NAHJ INTERFACE */ + GPIO76_GPIO | PIN_OUTPUT_LOW,/* NAHJ_CTRL */ + GPIO216_GPIO | PIN_OUTPUT_HIGH,/* NAHJ_CTRL_INV */ + + /* NFC INTERFACE */ + GPIO77_GPIO | PIN_OUTPUT_LOW, /* NFC_ENA */ + GPIO144_GPIO | PIN_INPUT_PULLDOWN, /* NFC_IRQ */ + GPIO142_GPIO | PIN_OUTPUT_LOW, /* NFC_RESET */ + + /* Keyboard MATRIX INTERFACE */ + GPIO90_MC5_CMD | PIN_OUTPUT_LOW, /* KP_O_1 */ + GPIO87_MC5_DAT1 | PIN_OUTPUT_LOW, /* KP_O_2 */ + GPIO86_MC5_DAT0 | PIN_OUTPUT_LOW, /* KP_O_3 */ + GPIO96_KP_O6 | PIN_OUTPUT_LOW, /* KP_O_6 */ + GPIO94_KP_O7 | PIN_OUTPUT_LOW, /* KP_O_7 */ + GPIO93_MC5_DAT4 | PIN_INPUT_PULLUP, /* KP_I_0 */ + GPIO89_MC5_DAT3 | PIN_INPUT_PULLUP, /* KP_I_2 */ + GPIO88_MC5_DAT2 | PIN_INPUT_PULLUP, /* KP_I_3 */ + GPIO91_GPIO | PIN_INPUT_PULLUP, /* FORCE_SENSING_INT */ + GPIO92_GPIO | PIN_OUTPUT_LOW, /* FORCE_SENSING_RST */ + GPIO97_GPIO | PIN_OUTPUT_LOW, /* FORCE_SENSING_WU */ + + /* DiPro Sensor Interface */ + GPIO139_GPIO | PIN_INPUT_PULLUP, /* DIPRO_INT */ + + /* HAL SWITCH INTERFACE */ + GPIO145_GPIO | PIN_INPUT_PULLDOWN,/* HAL_SW */ + + /* Audio Amplifier Interface */ + GPIO149_GPIO | PIN_OUTPUT_LOW, /* VAUDIO_HF_EN */ + + /* GBF INTERFACE */ + GPIO171_GPIO | PIN_OUTPUT_LOW, /* GBF_ENA_RESET */ + + /* MSP : HDTV INTERFACE */ + GPIO192_GPIO | PIN_INPUT_PULLDOWN, + + /* ACCELEROMETER_INTERFACE */ + GPIO82_GPIO | PIN_INPUT_PULLUP, /* ACC_INT1 */ + GPIO83_GPIO | PIN_INPUT_PULLUP, /* ACC_INT2 */ + + /* Proximity Sensor */ + GPIO217_GPIO | PIN_INPUT_PULLUP, + + +}; + +void __init mop500_pins_init(void) +{ + nmk_config_pins(mop500_pins_common, + ARRAY_SIZE(mop500_pins_common)); + if (machine_is_hrefv60()) + nmk_config_pins(mop500_pins_hrefv60, + ARRAY_SIZE(mop500_pins_hrefv60)); + else + nmk_config_pins(mop500_pins_default, + ARRAY_SIZE(mop500_pins_default)); +} diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index 1187f1fc2e53..875c91b2f8a4 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -3,99 +3,156 @@ * * License Terms: GNU General Public License v2 * - * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * Authors: Sundar Iyer <sundar.iyer@stericsson.com> + * Bengt Jonsson <bengt.g.jonsson@stericsson.com> * * MOP500 board specific initialization for regulators */ #include <linux/kernel.h> #include <linux/regulator/machine.h> +#include <linux/regulator/ab8500.h> +#include "board-mop500-regulators.h" -/* supplies to the display/camera */ -static struct regulator_init_data ab8500_vaux1_regulator = { - .constraints = { - .name = "V-DISPLAY", - .min_uV = 2500000, - .max_uV = 2900000, - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE| - REGULATOR_CHANGE_STATUS, - }, +static struct regulator_consumer_supply ab8500_vaux1_consumers[] = { + /* External displays, connector on board 2v5 power supply */ + REGULATOR_SUPPLY("vaux12v5", "mcde.0"), + /* SFH7741 proximity sensor */ + REGULATOR_SUPPLY("vcc", "gpio-keys.0"), + /* BH1780GLS ambient light sensor */ + REGULATOR_SUPPLY("vcc", "2-0029"), + /* lsm303dlh accelerometer */ + REGULATOR_SUPPLY("vdd", "3-0018"), + /* lsm303dlh magnetometer */ + REGULATOR_SUPPLY("vdd", "3-001e"), + /* Rohm BU21013 Touchscreen devices */ + REGULATOR_SUPPLY("avdd", "3-005c"), + REGULATOR_SUPPLY("avdd", "3-005d"), + /* Synaptics RMI4 Touchscreen device */ + REGULATOR_SUPPLY("vdd", "3-004b"), }; -/* supplies to the on-board eMMC */ -static struct regulator_init_data ab8500_vaux2_regulator = { - .constraints = { - .name = "V-eMMC1", - .min_uV = 1100000, - .max_uV = 3300000, - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE| - REGULATOR_CHANGE_STATUS, - }, +static struct regulator_consumer_supply ab8500_vaux2_consumers[] = { + /* On-board eMMC power */ + REGULATOR_SUPPLY("vmmc", "sdi4"), + /* AB8500 audio codec */ + REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"), }; -/* supply for VAUX3, supplies to SDcard slots */ -static struct regulator_init_data ab8500_vaux3_regulator = { - .constraints = { - .name = "V-MMC-SD", - .min_uV = 1100000, - .max_uV = 3300000, - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE| - REGULATOR_CHANGE_STATUS, - }, +static struct regulator_consumer_supply ab8500_vaux3_consumers[] = { + /* External MMC slot power */ + REGULATOR_SUPPLY("vmmc", "sdi0"), }; -/* supply for tvout, gpadc, TVOUT LDO */ -static struct regulator_init_data ab8500_vtvout_init = { - .constraints = { - .name = "V-TVOUT", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - }, +static struct regulator_consumer_supply ab8500_vtvout_consumers[] = { + /* TV-out DENC supply */ + REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"), + /* Internal general-purpose ADC */ + REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"), }; -/* supply for ab8500-vaudio, VAUDIO LDO */ -static struct regulator_init_data ab8500_vaudio_init = { - .constraints = { - .name = "V-AUD", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - }, +static struct regulator_consumer_supply ab8500_vintcore_consumers[] = { + /* SoC core supply, no device */ + REGULATOR_SUPPLY("v-intcore", NULL), + /* USB Transciever */ + REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"), }; -/* supply for v-anamic1 VAMic1-LDO */ -static struct regulator_init_data ab8500_vamic1_init = { - .constraints = { - .name = "V-AMIC1", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - }, +static struct regulator_consumer_supply ab8500_vana_consumers[] = { + /* External displays, connector on board, 1v8 power supply */ + REGULATOR_SUPPLY("vsmps2", "mcde.0"), }; -/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */ -static struct regulator_init_data ab8500_vamic2_init = { - .constraints = { - .name = "V-AMIC2", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, +/* AB8500 regulators */ +struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { + /* supplies to the display/camera */ + [AB8500_LDO_AUX1] = { + .constraints = { + .name = "V-DISPLAY", + .min_uV = 2500000, + .max_uV = 2900000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers), + .consumer_supplies = ab8500_vaux1_consumers, }, -}; - -/* supply for v-dmic, VDMIC LDO */ -static struct regulator_init_data ab8500_vdmic_init = { - .constraints = { - .name = "V-DMIC", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supplies to the on-board eMMC */ + [AB8500_LDO_AUX2] = { + .constraints = { + .name = "V-eMMC1", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers), + .consumer_supplies = ab8500_vaux2_consumers, }, -}; - -/* supply for v-intcore12, VINTCORE12 LDO */ -static struct regulator_init_data ab8500_vintcore_init = { - .constraints = { - .name = "V-INTCORE", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for VAUX3, supplies to SDcard slots */ + [AB8500_LDO_AUX3] = { + .constraints = { + .name = "V-MMC-SD", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers), + .consumer_supplies = ab8500_vaux3_consumers, }, -}; - -/* supply for U8500 CSI/DSI, VANA LDO */ -static struct regulator_init_data ab8500_vana_init = { - .constraints = { - .name = "V-CSI/DSI", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for tvout, gpadc, TVOUT LDO */ + [AB8500_LDO_TVOUT] = { + .constraints = { + .name = "V-TVOUT", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers), + .consumer_supplies = ab8500_vtvout_consumers, + }, + /* supply for ab8500-vaudio, VAUDIO LDO */ + [AB8500_LDO_AUDIO] = { + .constraints = { + .name = "V-AUD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + }, + /* supply for v-anamic1 VAMic1-LDO */ + [AB8500_LDO_ANAMIC1] = { + .constraints = { + .name = "V-AMIC1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + }, + /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */ + [AB8500_LDO_ANAMIC2] = { + .constraints = { + .name = "V-AMIC2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + }, + /* supply for v-dmic, VDMIC LDO */ + [AB8500_LDO_DMIC] = { + .constraints = { + .name = "V-DMIC", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + }, + /* supply for v-intcore12, VINTCORE12 LDO */ + [AB8500_LDO_INTCORE] = { + .constraints = { + .name = "V-INTCORE", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers), + .consumer_supplies = ab8500_vintcore_consumers, + }, + /* supply for U8500 CSI/DSI, VANA LDO */ + [AB8500_LDO_ANA] = { + .constraints = { + .name = "V-CSI/DSI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers), + .consumer_supplies = ab8500_vana_consumers, }, }; - diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h new file mode 100644 index 000000000000..2675fae52537 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-regulators.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + * + * MOP500 board specific initialization for regulators + */ + +#ifndef __BOARD_MOP500_REGULATORS_H +#define __BOARD_MOP500_REGULATORS_H + +#include <linux/regulator/machine.h> +#include <linux/regulator/ab8500.h> + +extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS]; + +#endif diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c index bac995665b58..bf0b02414e5b 100644 --- a/arch/arm/mach-ux500/board-mop500-sdi.c +++ b/arch/arm/mach-ux500/board-mop500-sdi.c @@ -12,59 +12,166 @@ #include <linux/mmc/host.h> #include <linux/platform_device.h> -#include <plat/pincfg.h> +#include <asm/mach-types.h> +#include <plat/ste_dma40.h> #include <mach/devices.h> #include <mach/hardware.h> -#include "pins-db8500.h" +#include "devices-db8500.h" #include "board-mop500.h" +#include "ste-dma40-db8500.h" -static pin_cfg_t mop500_sdi_pins[] = { - /* SDI4 (on-board eMMC) */ - GPIO197_MC4_DAT3, - GPIO198_MC4_DAT2, - GPIO199_MC4_DAT1, - GPIO200_MC4_DAT0, - GPIO201_MC4_CMD, - GPIO202_MC4_FBCLK, - GPIO203_MC4_CLK, - GPIO204_MC4_DAT7, - GPIO205_MC4_DAT6, - GPIO206_MC4_DAT5, - GPIO207_MC4_DAT4, +/* + * SDI 0 (MicroSD slot) + */ + +/* MMCIPOWER bits */ +#define MCI_DATA2DIREN (1 << 2) +#define MCI_CMDDIREN (1 << 3) +#define MCI_DATA0DIREN (1 << 4) +#define MCI_DATA31DIREN (1 << 5) +#define MCI_FBCLKEN (1 << 7) + +static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, + unsigned char power_mode) +{ + if (power_mode == MMC_POWER_UP) + gpio_set_value_cansleep(GPIO_SDMMC_EN, 1); + else if (power_mode == MMC_POWER_OFF) + gpio_set_value_cansleep(GPIO_SDMMC_EN, 0); + + return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN | + MCI_DATA2DIREN | MCI_DATA31DIREN; +} + +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg mop500_sdi0_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV29_SD_MM0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV29_SD_MM0_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, }; +#endif -static pin_cfg_t mop500_sdi2_pins[] = { - /* SDI2 (POP eMMC) */ - GPIO128_MC2_CLK, - GPIO129_MC2_CMD, - GPIO130_MC2_FBCLK, - GPIO131_MC2_DAT0, - GPIO132_MC2_DAT1, - GPIO133_MC2_DAT2, - GPIO134_MC2_DAT3, - GPIO135_MC2_DAT4, - GPIO136_MC2_DAT5, - GPIO137_MC2_DAT6, - GPIO138_MC2_DAT7, +static struct mmci_platform_data mop500_sdi0_data = { + .vdd_handler = mop500_sdi0_vdd_handler, + .ocr_mask = MMC_VDD_29_30, + .f_max = 100000000, + .capabilities = MMC_CAP_4_BIT_DATA, + .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &mop500_sdi0_dma_cfg_rx, + .dma_tx_param = &mop500_sdi0_dma_cfg_tx, +#endif }; +/* GPIO pins used by the sdi0 level shifter */ +static int sdi0_en = -1; +static int sdi0_vsel = -1; + +static void sdi0_configure(void) +{ + int ret; + + ret = gpio_request(sdi0_en, "level shifter enable"); + if (!ret) + ret = gpio_request(sdi0_vsel, + "level shifter 1v8-3v select"); + + if (ret) { + pr_warning("unable to config sdi0 gpios for level shifter.\n"); + return; + } + + /* Select the default 2.9V and enable level shifter */ + gpio_direction_output(sdi0_vsel, 0); + gpio_direction_output(sdi0_en, 1); + + /* Add the device */ + db8500_add_sdi0(&mop500_sdi0_data); +} + +void mop500_sdi_tc35892_init(void) +{ + mop500_sdi0_data.gpio_cd = GPIO_SDMMC_CD; + sdi0_en = GPIO_SDMMC_EN; + sdi0_vsel = GPIO_SDMMC_1V8_3V_SEL; + sdi0_configure(); +} + /* * SDI 2 (POP eMMC, not on DB8500ed) */ +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg mop500_sdi2_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV28_SD_MM2_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg mop500_sdi2_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV28_SD_MM2_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + static struct mmci_platform_data mop500_sdi2_data = { .ocr_mask = MMC_VDD_165_195, .f_max = 100000000, .capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, .gpio_cd = -1, .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &mop500_sdi2_dma_cfg_rx, + .dma_tx_param = &mop500_sdi2_dma_cfg_tx, +#endif }; /* * SDI 4 (on-board eMMC) */ +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg mop500_sdi4_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV42_SD_MM4_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg mop500_sdi4_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV42_SD_MM4_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + static struct mmci_platform_data mop500_sdi4_data = { .ocr_mask = MMC_VDD_29_30, .f_max = 100000000, @@ -72,20 +179,32 @@ static struct mmci_platform_data mop500_sdi4_data = { MMC_CAP_MMC_HIGHSPEED, .gpio_cd = -1, .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &mop500_sdi4_dma_cfg_rx, + .dma_tx_param = &mop500_sdi4_dma_cfg_tx, +#endif }; -void mop500_sdi_init(void) +void __init mop500_sdi_init(void) { - nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins)); + /* PoP:ed eMMC on top of DB8500 v1.0 has problems with high speed */ + if (!cpu_is_u8500v10()) + mop500_sdi2_data.capabilities |= MMC_CAP_MMC_HIGHSPEED; + db8500_add_sdi2(&mop500_sdi2_data); - u8500_sdi2_device.dev.platform_data = &mop500_sdi2_data; - u8500_sdi4_device.dev.platform_data = &mop500_sdi4_data; + /* On-board eMMC */ + db8500_add_sdi4(&mop500_sdi4_data); - if (!cpu_is_u8500ed()) { - nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins)); - amba_device_register(&u8500_sdi2_device, &iomem_resource); + if (machine_is_hrefv60()) { + mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO; + sdi0_en = HREFV60_SDMMC_EN_GPIO; + sdi0_vsel = HREFV60_SDMMC_1V8_3V_GPIO; + sdi0_configure(); } - - /* On-board eMMC */ - amba_device_register(&u8500_sdi4_device, &iomem_resource); + /* + * On boards with the TC35892 GPIO expander, sdi0 will finally + * be added when the TC35892 initializes and calls + * mop500_sdi_tc35892_init() above. + */ } diff --git a/arch/arm/mach-ux500/board-mop500-stuib.c b/arch/arm/mach-ux500/board-mop500-stuib.c new file mode 100644 index 000000000000..8c979770d872 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-stuib.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/mfd/stmpe.h> +#include <linux/input/bu21013.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/input/matrix_keypad.h> +#include <asm/mach-types.h> + +#include "board-mop500.h" + +/* STMPE/SKE keypad use this key layout */ +static const unsigned int mop500_keymap[] = { + KEY(2, 5, KEY_END), + KEY(4, 1, KEY_POWER), + KEY(3, 5, KEY_VOLUMEDOWN), + KEY(1, 3, KEY_3), + KEY(5, 2, KEY_RIGHT), + KEY(5, 0, KEY_9), + + KEY(0, 5, KEY_MENU), + KEY(7, 6, KEY_ENTER), + KEY(4, 5, KEY_0), + KEY(6, 7, KEY_2), + KEY(3, 4, KEY_UP), + KEY(3, 3, KEY_DOWN), + + KEY(6, 4, KEY_SEND), + KEY(6, 2, KEY_BACK), + KEY(4, 2, KEY_VOLUMEUP), + KEY(5, 5, KEY_1), + KEY(4, 3, KEY_LEFT), + KEY(3, 2, KEY_7), +}; + +static const struct matrix_keymap_data mop500_keymap_data = { + .keymap = mop500_keymap, + .keymap_size = ARRAY_SIZE(mop500_keymap), +}; +/* + * STMPE1601 + */ +static struct stmpe_keypad_platform_data stmpe1601_keypad_data = { + .debounce_ms = 64, + .scan_count = 8, + .no_autorepeat = true, + .keymap_data = &mop500_keymap_data, +}; + +static struct stmpe_platform_data stmpe1601_data = { + .id = 1, + .blocks = STMPE_BLOCK_KEYPAD, + .irq_trigger = IRQF_TRIGGER_FALLING, + .irq_base = MOP500_STMPE1601_IRQ(0), + .keypad = &stmpe1601_keypad_data, + .autosleep = true, + .autosleep_timeout = 1024, +}; + +static struct i2c_board_info __initdata mop500_i2c0_devices_stuib[] = { + { + I2C_BOARD_INFO("stmpe1601", 0x40), + .irq = NOMADIK_GPIO_TO_IRQ(218), + .platform_data = &stmpe1601_data, + .flags = I2C_CLIENT_WAKE, + }, +}; + +/* + * BU21013 ROHM touchscreen interface on the STUIBs + */ + +/* tracks number of bu21013 devices being enabled */ +static int bu21013_devices; + +#define TOUCH_GPIO_PIN 84 + +#define TOUCH_XMAX 384 +#define TOUCH_YMAX 704 + +#define PRCMU_CLOCK_OCR 0x1CC +#define TSC_EXT_CLOCK_9_6MHZ 0x840000 + +/** + * bu21013_gpio_board_init : configures the touch panel. + * @reset_pin: reset pin number + * This function can be used to configures + * the voltage and reset the touch panel controller. + */ +static int bu21013_gpio_board_init(int reset_pin) +{ + int retval = 0; + + bu21013_devices++; + if (bu21013_devices == 1) { + retval = gpio_request(reset_pin, "touchp_reset"); + if (retval) { + printk(KERN_ERR "Unable to request gpio reset_pin"); + return retval; + } + retval = gpio_direction_output(reset_pin, 1); + if (retval < 0) { + printk(KERN_ERR "%s: gpio direction failed\n", + __func__); + return retval; + } + } + + return retval; +} + +/** + * bu21013_gpio_board_exit : deconfigures the touch panel controller + * @reset_pin: reset pin number + * This function can be used to deconfigures the chip selection + * for touch panel controller. + */ +static int bu21013_gpio_board_exit(int reset_pin) +{ + int retval = 0; + + if (bu21013_devices == 1) { + retval = gpio_direction_output(reset_pin, 0); + if (retval < 0) { + printk(KERN_ERR "%s: gpio direction failed\n", + __func__); + return retval; + } + gpio_set_value(reset_pin, 0); + } + bu21013_devices--; + + return retval; +} + +/** + * bu21013_read_pin_val : get the interrupt pin value + * This function can be used to get the interrupt pin value for touch panel + * controller. + */ +static int bu21013_read_pin_val(void) +{ + return gpio_get_value(TOUCH_GPIO_PIN); +} + +static struct bu21013_platform_device tsc_plat_device = { + .cs_en = bu21013_gpio_board_init, + .cs_dis = bu21013_gpio_board_exit, + .irq_read_val = bu21013_read_pin_val, + .irq = NOMADIK_GPIO_TO_IRQ(TOUCH_GPIO_PIN), + .touch_x_max = TOUCH_XMAX, + .touch_y_max = TOUCH_YMAX, + .ext_clk = false, + .x_flip = false, + .y_flip = true, +}; + +static struct bu21013_platform_device tsc_plat2_device = { + .cs_en = bu21013_gpio_board_init, + .cs_dis = bu21013_gpio_board_exit, + .irq_read_val = bu21013_read_pin_val, + .irq = NOMADIK_GPIO_TO_IRQ(TOUCH_GPIO_PIN), + .touch_x_max = TOUCH_XMAX, + .touch_y_max = TOUCH_YMAX, + .ext_clk = false, + .x_flip = false, + .y_flip = true, +}; + +static struct i2c_board_info __initdata u8500_i2c3_devices_stuib[] = { + { + I2C_BOARD_INFO("bu21013_tp", 0x5C), + .platform_data = &tsc_plat_device, + }, + { + I2C_BOARD_INFO("bu21013_tp", 0x5D), + .platform_data = &tsc_plat2_device, + }, + +}; + +void __init mop500_stuib_init(void) +{ + if (machine_is_hrefv60()) { + tsc_plat_device.cs_pin = HREFV60_TOUCH_RST_GPIO; + tsc_plat2_device.cs_pin = HREFV60_TOUCH_RST_GPIO; + } else { + tsc_plat_device.cs_pin = GPIO_BU21013_CS; + tsc_plat2_device.cs_pin = GPIO_BU21013_CS; + + } + + mop500_uib_i2c_add(0, mop500_i2c0_devices_stuib, + ARRAY_SIZE(mop500_i2c0_devices_stuib)); + + mop500_uib_i2c_add(3, u8500_i2c3_devices_stuib, + ARRAY_SIZE(u8500_i2c3_devices_stuib)); +} diff --git a/arch/arm/mach-ux500/board-mop500-u8500uib.c b/arch/arm/mach-ux500/board-mop500-u8500uib.c new file mode 100644 index 000000000000..d8a8734a0eba --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-u8500uib.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Board data for the U8500 UIB, also known as the New UIB + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/mfd/tc3589x.h> +#include <linux/input/matrix_keypad.h> +#include <../drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h> + +#include <mach/gpio.h> +#include <mach/irqs.h> + +#include "board-mop500.h" + +/* + * Synaptics RMI4 touchscreen interface on the U8500 UIB + */ + +/* + * Descriptor structure. + * Describes the number of i2c devices on the bus that speak RMI. + */ +static struct synaptics_rmi4_platform_data rmi4_i2c_dev_platformdata = { + .irq_number = NOMADIK_GPIO_TO_IRQ(84), + .irq_type = (IRQF_TRIGGER_FALLING | IRQF_SHARED), + .x_flip = false, + .y_flip = true, + .regulator_en = false, +}; + +static struct i2c_board_info __initdata mop500_i2c3_devices_u8500[] = { + { + I2C_BOARD_INFO("synaptics_rmi4_i2c", 0x4B), + .platform_data = &rmi4_i2c_dev_platformdata, + }, +}; + +/* + * TC35893 + */ +static const unsigned int u8500_keymap[] = { + KEY(3, 1, KEY_END), + KEY(4, 1, KEY_POWER), + KEY(6, 4, KEY_VOLUMEDOWN), + KEY(4, 2, KEY_EMAIL), + KEY(3, 3, KEY_RIGHT), + KEY(2, 5, KEY_BACKSPACE), + + KEY(6, 7, KEY_MENU), + KEY(5, 0, KEY_ENTER), + KEY(4, 3, KEY_0), + KEY(3, 4, KEY_DOT), + KEY(5, 2, KEY_UP), + KEY(3, 5, KEY_DOWN), + + KEY(4, 5, KEY_SEND), + KEY(0, 5, KEY_BACK), + KEY(6, 2, KEY_VOLUMEUP), + KEY(1, 3, KEY_SPACE), + KEY(7, 6, KEY_LEFT), + KEY(5, 5, KEY_SEARCH), +}; + +static struct matrix_keymap_data u8500_keymap_data = { + .keymap = u8500_keymap, + .keymap_size = ARRAY_SIZE(u8500_keymap), +}; + +static struct tc3589x_keypad_platform_data tc35893_data = { + .krow = TC_KPD_ROWS, + .kcol = TC_KPD_COLUMNS, + .debounce_period = TC_KPD_DEBOUNCE_PERIOD, + .settle_time = TC_KPD_SETTLE_TIME, + .irqtype = IRQF_TRIGGER_FALLING, + .enable_wakeup = true, + .keymap_data = &u8500_keymap_data, + .no_autorepeat = true, +}; + +static struct tc3589x_platform_data tc3589x_keypad_data = { + .block = TC3589x_BLOCK_KEYPAD, + .keypad = &tc35893_data, + .irq_base = MOP500_EGPIO_IRQ_BASE, +}; + +static struct i2c_board_info __initdata mop500_i2c0_devices_u8500[] = { + { + I2C_BOARD_INFO("tc3589x", 0x44), + .platform_data = &tc3589x_keypad_data, + .irq = NOMADIK_GPIO_TO_IRQ(218), + .flags = I2C_CLIENT_WAKE, + }, +}; + + +void __init mop500_u8500uib_init(void) +{ + mop500_uib_i2c_add(3, mop500_i2c3_devices_u8500, + ARRAY_SIZE(mop500_i2c3_devices_u8500)); + + mop500_uib_i2c_add(0, mop500_i2c0_devices_u8500, + ARRAY_SIZE(mop500_i2c0_devices_u8500)); + +} diff --git a/arch/arm/mach-ux500/board-mop500-uib.c b/arch/arm/mach-ux500/board-mop500-uib.c new file mode 100644 index 000000000000..69cce41f602a --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-uib.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2 + */ + +#define pr_fmt(fmt) "mop500-uib: " fmt + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/i2c.h> + +#include <mach/hardware.h> +#include "board-mop500.h" + +enum mop500_uib { + STUIB, + U8500UIB, +}; + +struct uib { + const char *name; + const char *option; + void (*init)(void); +}; + +static struct __initdata uib mop500_uibs[] = { + [STUIB] = { + .name = "ST-UIB", + .option = "stuib", + .init = mop500_stuib_init, + }, + [U8500UIB] = { + .name = "U8500-UIB", + .option = "u8500uib", + .init = mop500_u8500uib_init, + }, +}; + +static struct uib *mop500_uib; + +static int __init mop500_uib_setup(char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mop500_uibs); i++) { + struct uib *uib = &mop500_uibs[i]; + + if (!strcmp(str, uib->option)) { + mop500_uib = uib; + break; + } + } + + if (i == ARRAY_SIZE(mop500_uibs)) + pr_err("invalid uib= option (%s)\n", str); + + return 1; +} +__setup("uib=", mop500_uib_setup); + +/* + * The UIBs are detected after the I2C host controllers are registered, so + * i2c_register_board_info() can't be used. + */ +void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info, + unsigned n) +{ + struct i2c_adapter *adap; + struct i2c_client *client; + int i; + + adap = i2c_get_adapter(busnum); + if (!adap) { + pr_err("failed to get adapter i2c%d\n", busnum); + return; + } + + for (i = 0; i < n; i++) { + client = i2c_new_device(adap, &info[i]); + if (!client) + pr_err("failed to register %s to i2c%d\n", + info[i].type, busnum); + } + + i2c_put_adapter(adap); +} + +static void __init __mop500_uib_init(struct uib *uib, const char *why) +{ + pr_info("%s (%s)\n", uib->name, why); + uib->init(); +} + +/* + * Detect the UIB attached based on the presence or absence of i2c devices. + */ +static int __init mop500_uib_init(void) +{ + struct uib *uib = mop500_uib; + struct i2c_adapter *i2c0; + int ret; + + if (!cpu_is_u8500()) + return -ENODEV; + + if (uib) { + __mop500_uib_init(uib, "from uib= boot argument"); + return 0; + } + + i2c0 = i2c_get_adapter(0); + if (!i2c0) { + __mop500_uib_init(&mop500_uibs[STUIB], + "fallback, could not get i2c0"); + return -ENODEV; + } + + /* U8500-UIB has the TC35893 at 0x44 on I2C0, the ST-UIB doesn't. */ + ret = i2c_smbus_xfer(i2c0, 0x44, 0, I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL); + i2c_put_adapter(i2c0); + + if (ret == 0) + uib = &mop500_uibs[U8500UIB]; + else + uib = &mop500_uibs[STUIB]; + + __mop500_uib_init(uib, "detected"); + + return 0; +} + +module_init(mop500_uib_init); diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index cac83a694880..8790d984cac8 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -13,89 +13,45 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/i2c.h> #include <linux/gpio.h> #include <linux/amba/bus.h> #include <linux/amba/pl022.h> +#include <linux/amba/serial.h> #include <linux/spi/spi.h> #include <linux/mfd/ab8500.h> -#include <linux/input/matrix_keypad.h> +#include <linux/mfd/tc3589x.h> +#include <linux/leds-lp5521.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> -#include <plat/pincfg.h> #include <plat/i2c.h> -#include <plat/ske.h> +#include <plat/ste_dma40.h> #include <mach/hardware.h> #include <mach/setup.h> #include <mach/devices.h> #include <mach/irqs.h> -#include "pins-db8500.h" +#include "ste-dma40-db8500.h" +#include "devices-db8500.h" #include "board-mop500.h" - -static pin_cfg_t mop500_pins[] = { - /* SSP0 */ - GPIO143_SSP0_CLK, - GPIO144_SSP0_FRM, - GPIO145_SSP0_RXD, - GPIO146_SSP0_TXD, - - /* I2C */ - GPIO147_I2C0_SCL, - GPIO148_I2C0_SDA, - GPIO16_I2C1_SCL, - GPIO17_I2C1_SDA, - GPIO10_I2C2_SDA, - GPIO11_I2C2_SCL, - GPIO229_I2C3_SDA, - GPIO230_I2C3_SCL, - - /* SKE keypad */ - GPIO153_KP_I7, - GPIO154_KP_I6, - GPIO155_KP_I5, - GPIO156_KP_I4, - GPIO157_KP_O7, - GPIO158_KP_O6, - GPIO159_KP_O5, - GPIO160_KP_O4, - GPIO161_KP_I3, - GPIO162_KP_I2, - GPIO163_KP_I1, - GPIO164_KP_I0, - GPIO165_KP_O3, - GPIO166_KP_O2, - GPIO167_KP_O1, - GPIO168_KP_O0, -}; - -static void ab4500_spi_cs_control(u32 command) -{ - /* set the FRM signal, which is CS - TODO */ -} - -struct pl022_config_chip ab4500_chip_info = { - .com_mode = INTERRUPT_TRANSFER, - .iface = SSP_INTERFACE_MOTOROLA_SPI, - /* we can act as master only */ - .hierarchy = SSP_MASTER, - .slave_tx_disable = 0, - .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, - .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, - .cs_control = ab4500_spi_cs_control, -}; +#include "board-mop500-regulators.h" static struct ab8500_platform_data ab8500_platdata = { .irq_base = MOP500_AB8500_IRQ_BASE, + .regulator = ab8500_regulators, + .num_regulator = ARRAY_SIZE(ab8500_regulators), }; static struct resource ab8500_resources[] = { [0] = { - .start = IRQ_AB8500, - .end = IRQ_AB8500, - .flags = IORESOURCE_IRQ + .start = IRQ_DB8500_AB8500, + .end = IRQ_DB8500_AB8500, + .flags = IORESOURCE_IRQ } }; @@ -109,27 +65,99 @@ struct platform_device ab8500_device = { .resource = ab8500_resources, }; -static struct spi_board_info ab8500_spi_devices[] = { +/* + * TC35892 + */ + +static void mop500_tc35892_init(struct tc3589x *tc3589x, unsigned int base) +{ + mop500_sdi_tc35892_init(); +} + +static struct tc3589x_gpio_platform_data mop500_tc35892_gpio_data = { + .gpio_base = MOP500_EGPIO(0), + .setup = mop500_tc35892_init, +}; + +static struct tc3589x_platform_data mop500_tc35892_data = { + .block = TC3589x_BLOCK_GPIO, + .gpio = &mop500_tc35892_gpio_data, + .irq_base = MOP500_EGPIO_IRQ_BASE, +}; + +static struct lp5521_led_config lp5521_pri_led[] = { + [0] = { + .chan_nr = 0, + .led_current = 0x2f, + .max_current = 0x5f, + }, + [1] = { + .chan_nr = 1, + .led_current = 0x2f, + .max_current = 0x5f, + }, + [2] = { + .chan_nr = 2, + .led_current = 0x2f, + .max_current = 0x5f, + }, +}; + +static struct lp5521_platform_data __initdata lp5521_pri_data = { + .label = "lp5521_pri", + .led_config = &lp5521_pri_led[0], + .num_channels = 3, + .clock_mode = LP5521_CLOCK_EXT, +}; + +static struct lp5521_led_config lp5521_sec_led[] = { + [0] = { + .chan_nr = 0, + .led_current = 0x2f, + .max_current = 0x5f, + }, + [1] = { + .chan_nr = 1, + .led_current = 0x2f, + .max_current = 0x5f, + }, + [2] = { + .chan_nr = 2, + .led_current = 0x2f, + .max_current = 0x5f, + }, +}; + +static struct lp5521_platform_data __initdata lp5521_sec_data = { + .label = "lp5521_sec", + .led_config = &lp5521_sec_led[0], + .num_channels = 3, + .clock_mode = LP5521_CLOCK_EXT, +}; + +static struct i2c_board_info mop500_i2c0_devices[] = { { - .modalias = "ab8500-spi", - .controller_data = &ab4500_chip_info, - .platform_data = &ab8500_platdata, - .max_speed_hz = 12000000, - .bus_num = 0, - .chip_select = 0, - .mode = SPI_MODE_3, - .irq = IRQ_DB8500_AB8500, + I2C_BOARD_INFO("tc3589x", 0x42), + .irq = NOMADIK_GPIO_TO_IRQ(217), + .platform_data = &mop500_tc35892_data, }, }; -static struct pl022_ssp_controller ssp0_platform_data = { - .bus_id = 0, - /* pl022 not yet supports dma */ - .enable_dma = 0, - /* on this platform, gpio 31,142,144,214 & - * 224 are connected as chip selects - */ - .num_chipselect = 5, +static struct i2c_board_info __initdata mop500_i2c2_devices[] = { + { + /* lp5521 LED driver, 1st device */ + I2C_BOARD_INFO("lp5521", 0x33), + .platform_data = &lp5521_pri_data, + }, + { + /* lp5521 LED driver, 2st device */ + I2C_BOARD_INFO("lp5521", 0x34), + .platform_data = &lp5521_sec_data, + }, + { + /* Light sensor Rohm BH1780GLI */ + I2C_BOARD_INFO("bh1780", 0x29), + }, }; #define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \ @@ -161,159 +189,224 @@ U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); -static struct amba_device *amba_devs[] __initdata = { - &ux500_uart0_device, - &ux500_uart1_device, - &ux500_uart2_device, - &u8500_ssp0_device, -}; +static void __init mop500_i2c_init(void) +{ + db8500_add_i2c0(&u8500_i2c0_data); + db8500_add_i2c1(&u8500_i2c1_data); + db8500_add_i2c2(&u8500_i2c2_data); + db8500_add_i2c3(&u8500_i2c3_data); +} -static const unsigned int ux500_keymap[] = { - KEY(2, 5, KEY_END), - KEY(4, 1, KEY_POWER), - KEY(3, 5, KEY_VOLUMEDOWN), - KEY(1, 3, KEY_3), - KEY(5, 2, KEY_RIGHT), - KEY(5, 0, KEY_9), - - KEY(0, 5, KEY_MENU), - KEY(7, 6, KEY_ENTER), - KEY(4, 5, KEY_0), - KEY(6, 7, KEY_2), - KEY(3, 4, KEY_UP), - KEY(3, 3, KEY_DOWN), - - KEY(6, 4, KEY_SEND), - KEY(6, 2, KEY_BACK), - KEY(4, 2, KEY_VOLUMEUP), - KEY(5, 5, KEY_1), - KEY(4, 3, KEY_LEFT), - KEY(3, 2, KEY_7), +static struct gpio_keys_button mop500_gpio_keys[] = { + { + .desc = "SFH7741 Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .active_low = 0, + .can_disable = 1, + } }; -static const struct matrix_keymap_data ux500_keymap_data = { - .keymap = ux500_keymap, - .keymap_size = ARRAY_SIZE(ux500_keymap), +static struct regulator *prox_regulator; +static int mop500_prox_activate(struct device *dev); +static void mop500_prox_deactivate(struct device *dev); + +static struct gpio_keys_platform_data mop500_gpio_keys_data = { + .buttons = mop500_gpio_keys, + .nbuttons = ARRAY_SIZE(mop500_gpio_keys), + .enable = mop500_prox_activate, + .disable = mop500_prox_deactivate, }; -/* - * Nomadik SKE keypad - */ -#define ROW_PIN_I0 164 -#define ROW_PIN_I1 163 -#define ROW_PIN_I2 162 -#define ROW_PIN_I3 161 -#define ROW_PIN_I4 156 -#define ROW_PIN_I5 155 -#define ROW_PIN_I6 154 -#define ROW_PIN_I7 153 -#define COL_PIN_O0 168 -#define COL_PIN_O1 167 -#define COL_PIN_O2 166 -#define COL_PIN_O3 165 -#define COL_PIN_O4 160 -#define COL_PIN_O5 159 -#define COL_PIN_O6 158 -#define COL_PIN_O7 157 - -#define SKE_KPD_MAX_ROWS 8 -#define SKE_KPD_MAX_COLS 8 - -static int ske_kp_rows[] = { - ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3, - ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7, +static struct platform_device mop500_gpio_keys_device = { + .name = "gpio-keys", + .id = 0, + .dev = { + .platform_data = &mop500_gpio_keys_data, + }, }; -/* - * ske_set_gpio_row: request and set gpio rows - */ -static int ske_set_gpio_row(int gpio) +static int mop500_prox_activate(struct device *dev) { - int ret; - - ret = gpio_request(gpio, "ske-kp"); - if (ret < 0) { - pr_err("ske_set_gpio_row: gpio request failed\n"); - return ret; + prox_regulator = regulator_get(&mop500_gpio_keys_device.dev, + "vcc"); + if (IS_ERR(prox_regulator)) { + dev_err(&mop500_gpio_keys_device.dev, + "no regulator\n"); + return PTR_ERR(prox_regulator); } - - ret = gpio_direction_output(gpio, 1); - if (ret < 0) { - pr_err("ske_set_gpio_row: gpio direction failed\n"); - gpio_free(gpio); - } - - return ret; + regulator_enable(prox_regulator); + return 0; } -/* - * ske_kp_init - enable the gpio configuration - */ -static int ske_kp_init(void) +static void mop500_prox_deactivate(struct device *dev) { - int ret, i; - - for (i = 0; i < SKE_KPD_MAX_ROWS; i++) { - ret = ske_set_gpio_row(ske_kp_rows[i]); - if (ret < 0) { - pr_err("ske_kp_init: failed init\n"); - return ret; - } - } - - return 0; + regulator_disable(prox_regulator); + regulator_put(prox_regulator); } -static struct ske_keypad_platform_data ske_keypad_board = { - .init = ske_kp_init, - .keymap_data = &ux500_keymap_data, - .no_autorepeat = true, - .krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */ - .kcol = SKE_KPD_MAX_COLS, - .debounce_ms = 40, /* in millsecs */ +/* add any platform devices here - TODO */ +static struct platform_device *platform_devs[] __initdata = { + &mop500_gpio_keys_device, }; +#ifdef CONFIG_STE_DMA40 +static struct stedma40_chan_cfg ssp0_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV8_SSP0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.data_width = STEDMA40_BYTE_WIDTH, +}; +static struct stedma40_chan_cfg ssp0_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV8_SSP0_TX, + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.data_width = STEDMA40_BYTE_WIDTH, +}; +#endif -/* add any platform devices here - TODO */ -static struct platform_device *platform_devs[] __initdata = { - &u8500_i2c0_device, - &ux500_i2c1_device, - &ux500_i2c2_device, - &ux500_i2c3_device, - &ux500_ske_keypad_device, +static struct pl022_ssp_controller ssp0_platform_data = { + .bus_id = 0, +#ifdef CONFIG_STE_DMA40 + .enable_dma = 1, + .dma_filter = stedma40_filter, + .dma_rx_param = &ssp0_dma_cfg_rx, + .dma_tx_param = &ssp0_dma_cfg_tx, +#else + .enable_dma = 0, +#endif + /* on this platform, gpio 31,142,144,214 & + * 224 are connected as chip selects + */ + .num_chipselect = 5, }; -static void __init u8500_init_machine(void) +static void __init mop500_spi_init(void) { - int i; + db8500_add_ssp0(&ssp0_platform_data); +} - u8500_init_devices(); +#ifdef CONFIG_STE_DMA40 +static struct stedma40_chan_cfg uart0_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV13_UART0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.data_width = STEDMA40_BYTE_WIDTH, +}; - nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins)); +static struct stedma40_chan_cfg uart0_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV13_UART0_TX, + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.data_width = STEDMA40_BYTE_WIDTH, +}; - u8500_i2c0_device.dev.platform_data = &u8500_i2c0_data; - ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data; - ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data; - ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data; - ux500_ske_keypad_device.dev.platform_data = &ske_keypad_board; +static struct stedma40_chan_cfg uart1_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV12_UART1_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.data_width = STEDMA40_BYTE_WIDTH, +}; - u8500_ssp0_device.dev.platform_data = &ssp0_platform_data; +static struct stedma40_chan_cfg uart1_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV12_UART1_TX, + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.data_width = STEDMA40_BYTE_WIDTH, +}; + +static struct stedma40_chan_cfg uart2_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB8500_DMA_DEV11_UART2_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.data_width = STEDMA40_BYTE_WIDTH, +}; - /* Register the active AMBA devices on this board */ - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) - amba_device_register(amba_devs[i], &iomem_resource); +static struct stedma40_chan_cfg uart2_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB8500_DMA_DEV11_UART2_TX, + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.data_width = STEDMA40_BYTE_WIDTH, +}; +#endif + +static struct amba_pl011_data uart0_plat = { +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &uart0_dma_cfg_rx, + .dma_tx_param = &uart0_dma_cfg_tx, +#endif +}; + +static struct amba_pl011_data uart1_plat = { +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &uart1_dma_cfg_rx, + .dma_tx_param = &uart1_dma_cfg_tx, +#endif +}; + +static struct amba_pl011_data uart2_plat = { +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &uart2_dma_cfg_rx, + .dma_tx_param = &uart2_dma_cfg_tx, +#endif +}; + +static void __init mop500_uart_init(void) +{ + db8500_add_uart0(&uart0_plat); + db8500_add_uart1(&uart1_plat); + db8500_add_uart2(&uart2_plat); +} + +static void __init mop500_init_machine(void) +{ + /* + * The HREFv60 board removed a GPIO expander and routed + * all these GPIO pins to the internal GPIO controller + * instead. + */ + if (machine_is_hrefv60()) + mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO; + else + mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR; + + u8500_init_devices(); + + mop500_pins_init(); platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); + mop500_i2c_init(); mop500_sdi_init(); + mop500_spi_init(); + mop500_uart_init(); + + platform_device_register(&ab8500_device); - /* If HW is early drop (ED) or V1.0 then use SPI to access AB8500 */ - if (cpu_is_u8500ed() || cpu_is_u8500v10()) - spi_register_board_info(ab8500_spi_devices, - ARRAY_SIZE(ab8500_spi_devices)); - else /* If HW is v.1.1 or later use I2C to access AB8500 */ - platform_device_register(&ab8500_device); + i2c_register_board_info(0, mop500_i2c0_devices, + ARRAY_SIZE(mop500_i2c0_devices)); + i2c_register_board_info(2, mop500_i2c2_devices, + ARRAY_SIZE(mop500_i2c2_devices)); } MACHINE_START(U8500, "ST-Ericsson MOP500 platform") @@ -323,5 +416,13 @@ MACHINE_START(U8500, "ST-Ericsson MOP500 platform") .init_irq = ux500_init_irq, /* we re-use nomadik timer here */ .timer = &ux500_timer, - .init_machine = u8500_init_machine, + .init_machine = mop500_init_machine, +MACHINE_END + +MACHINE_START(HREFV60, "ST-Ericsson U8500 Platform HREFv60+") + .boot_params = 0x100, + .map_io = u8500_map_io, + .init_irq = ux500_init_irq, + .timer = &ux500_timer, + .init_machine = mop500_init_machine, MACHINE_END diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index 2d240322fa6f..56722f4be71b 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h @@ -7,6 +7,36 @@ #ifndef __BOARD_MOP500_H #define __BOARD_MOP500_H +/* HREFv60-specific GPIO assignments, this board has no GPIO expander */ +#define HREFV60_TOUCH_RST_GPIO 143 +#define HREFV60_PROX_SENSE_GPIO 217 +#define HREFV60_HAL_SW_GPIO 145 +#define HREFV60_SDMMC_EN_GPIO 169 +#define HREFV60_SDMMC_1V8_3V_GPIO 5 +#define HREFV60_SDMMC_CD_GPIO 95 +#define HREFV60_ACCEL_INT1_GPIO 82 +#define HREFV60_ACCEL_INT2_GPIO 83 +#define HREFV60_MAGNET_DRDY_GPIO 32 +#define HREFV60_DISP1_RST_GPIO 65 +#define HREFV60_DISP2_RST_GPIO 66 + +/* GPIOs on the TC35892 expander */ +#define MOP500_EGPIO(x) (NOMADIK_NR_GPIO + (x)) +#define GPIO_SDMMC_CD MOP500_EGPIO(3) +#define GPIO_PROX_SENSOR MOP500_EGPIO(7) +#define GPIO_BU21013_CS MOP500_EGPIO(13) +#define GPIO_SDMMC_EN MOP500_EGPIO(17) +#define GPIO_SDMMC_1V8_3V_SEL MOP500_EGPIO(18) + +struct i2c_board_info; + extern void mop500_sdi_init(void); +extern void mop500_sdi_tc35892_init(void); +void __init mop500_u8500uib_init(void); +void __init mop500_stuib_init(void); +void __init mop500_pins_init(void); + +void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info, + unsigned n); #endif diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c new file mode 100644 index 000000000000..739fb4c5b160 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-sdi.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Hanumath Prasad <ulf.hansson@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/amba/mmci.h> +#include <linux/mmc/host.h> +#include <linux/gpio.h> + +#include <plat/pincfg.h> +#include <mach/db5500-regs.h> +#include <plat/ste_dma40.h> + +#include "pins-db5500.h" +#include "devices-db5500.h" +#include "ste-dma40-db5500.h" + +static pin_cfg_t u5500_sdi_pins[] = { + /* SDI0 (POP eMMC) */ + GPIO5_MC0_DAT0 | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO6_MC0_DAT1 | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO7_MC0_DAT2 | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO8_MC0_DAT3 | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO9_MC0_DAT4 | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO10_MC0_DAT5 | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO11_MC0_DAT6 | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO12_MC0_DAT7 | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO13_MC0_CMD | PIN_DIR_INPUT | PIN_PULL_UP, + GPIO14_MC0_CLK | PIN_DIR_OUTPUT | PIN_VAL_LOW, +}; + +#ifdef CONFIG_STE_DMA40 +struct stedma40_chan_cfg u5500_sdi0_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV24_SDMMC0_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg u5500_sdi0_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV24_SDMMC0_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static struct mmci_platform_data u5500_sdi0_data = { + .ocr_mask = MMC_VDD_165_195, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_8_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED, + .gpio_cd = -1, + .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &u5500_sdi0_dma_cfg_rx, + .dma_tx_param = &u5500_sdi0_dma_cfg_tx, +#endif +}; + +void __init u5500_sdi_init(void) +{ + nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins)); + + db5500_add_sdi0(&u5500_sdi0_data); +} diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index 1ca094a45e71..44fd3b5c33ec 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c @@ -9,6 +9,7 @@ #include <linux/platform_device.h> #include <linux/amba/bus.h> #include <linux/gpio.h> +#include <linux/irq.h> #include <asm/mach/arch.h> #include <asm/mach-types.h> @@ -17,20 +18,24 @@ #include <mach/devices.h> #include <mach/setup.h> -static struct amba_device *amba_board_devs[] __initdata = { - &ux500_uart0_device, - &ux500_uart1_device, - &ux500_uart2_device, -}; +#include "devices-db5500.h" + +static void __init u5500_uart_init(void) +{ + db5500_add_uart0(NULL); + db5500_add_uart1(NULL); + db5500_add_uart2(NULL); +} static void __init u5500_init_machine(void) { u5500_init_devices(); - amba_add_devices(amba_board_devs, ARRAY_SIZE(amba_board_devs)); + u5500_sdi_init(); + u5500_uart_init(); } -MACHINE_START(U8500, "ST-Ericsson U5500 Platform") +MACHINE_START(U5500, "ST-Ericsson U5500 Platform") .boot_params = 0x00000100, .map_io = u5500_map_io, .init_irq = ux500_init_irq, diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 1675047daf20..32ce90840ee1 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -13,13 +13,18 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> - -#include <asm/clkdev.h> +#include <linux/clkdev.h> #include <plat/mtu.h> #include <mach/hardware.h> #include "clock.h" +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> +#include <linux/uaccess.h> /* for copy_from_user */ +static LIST_HEAD(clk_list); +#endif + #define PRCC_PCKEN 0x00 #define PRCC_PCKDIS 0x04 #define PRCC_KCKEN 0x08 @@ -131,9 +136,8 @@ EXPORT_SYMBOL(clk_disable); */ static unsigned long clk_mtu_get_rate(struct clk *clk) { - void __iomem *addr = __io_address(UX500_PRCMU_BASE) - + PRCM_TCR; - u32 tcr = readl(addr); + void __iomem *addr; + u32 tcr; int mtu = (int) clk->data; /* * One of these is selected eventually @@ -144,6 +148,21 @@ static unsigned long clk_mtu_get_rate(struct clk *clk) unsigned long mturate; unsigned long retclk; + if (cpu_is_u5500()) + addr = __io_address(U5500_PRCMU_BASE); + else if (cpu_is_u8500()) + addr = __io_address(U8500_PRCMU_BASE); + else + ux500_unknown_soc(); + + /* + * On a startup, always conifgure the TCR to the doze mode; + * bootloaders do it for us. Do this in the kernel too. + */ + writel(PRCM_TCR_DOZE_MODE, addr + PRCM_TCR); + + tcr = readl(addr + PRCM_TCR); + /* Get the rate from the parent as a default */ if (clk->parent_periph) mturate = clk_get_rate(clk->parent_periph); @@ -153,45 +172,6 @@ static unsigned long clk_mtu_get_rate(struct clk *clk) /* We need to be connected SOMEWHERE */ BUG(); - /* - * Are we in doze mode? - * In this mode the parent peripheral or the fixed 32768 Hz - * clock is fed into the block. - */ - if (!(tcr & PRCM_TCR_DOZE_MODE)) { - /* - * Here we're using the clock input from the APE ULP - * clock domain. But first: are the timers stopped? - */ - if (tcr & PRCM_TCR_STOPPED) { - clk32k = 0; - mturate = 0; - } else { - /* Else default mode: 0 and 2.4 MHz */ - clk32k = 0; - if (cpu_is_u5500()) - /* DB5500 divides by 8 */ - mturate /= 8; - else if (cpu_is_u8500ed()) { - /* - * This clocking setting must not be used - * in the ED chip, it is simply not - * connected anywhere! - */ - mturate = 0; - BUG(); - } else - /* - * In this mode the ulp38m4 clock is divided - * by a factor 16, on the DB8500 typically - * 38400000 / 16 ~ 2.4 MHz. - * TODO: Replace the constant with a reference - * to the ULP source once this is modeled. - */ - mturate = 38400000 / 16; - } - } - /* Return the clock selected for this MTU */ if (tcr & (1 << mtu)) retclk = clk32k; @@ -317,6 +297,7 @@ static struct clkops clk_prcc_ops = { }; static struct clk clk_32khz = { + .name = "clk_32khz", .rate = 32000, }; @@ -332,7 +313,7 @@ static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000); static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK); static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */ static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000); -static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 50000000); +static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 100000000); static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK); static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK); static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK); @@ -366,94 +347,96 @@ static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */ */ /* Peripheral Cluster #1 */ -static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk); +static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk); static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL); -static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk); -static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL); -static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL); -static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk); +static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk); +static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL); +static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL); +static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk); static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk); -static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk); -static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk); -static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk); -static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk); -static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk); +static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk); +static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk); +static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk); +static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk); +static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk); +static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk); /* Peripheral Cluster #2 */ static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL); -static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL); -static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL); -static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL); -static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk); -static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL); +static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL); +static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL); +static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk); +static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk); static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL); -static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL); -static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL); -static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk); +static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL); +static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL); +static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk); static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL); -static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL); -static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL); -static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL); -static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk); -static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL); +static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL); +static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL); +static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk); +static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk); static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL); -static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL); -static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL); -static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk); +static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL); +static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL); +static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk); /* Peripheral Cluster #3 */ -static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL); -static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk); -static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz); -static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk); -static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk); -static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk); -static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk); -static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk); -static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk); -static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL); +static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL); +static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk); +static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz); +static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk); +static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk); +static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk); +static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk); +static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk); +static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk); +static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL); /* Peripheral Cluster #4 is in the always on domain */ /* Peripheral Cluster #5 */ -static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL); -static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk); -static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); +static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL); +static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk); +static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); /* Peripheral Cluster #6 */ /* MTU ID in data */ static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1); static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0); -static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); -static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); -static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); -static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk); -static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL); -static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL); -static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL); -static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL); -static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk); -static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); +static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); +static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); +static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); +static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk); +static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL); +static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL); +static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL); +static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL); +static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk); +static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); /* Peripheral Cluster #7 */ -static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); +static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); /* MTU ID in data */ static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1); static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0); -static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); -static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); +static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); +static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); -static struct clk clk_dummy_apb_pclk; +static struct clk clk_dummy_apb_pclk = { + .name = "apb_pclk", +}; static struct clk_lookup u8500_common_clks[] = { CLK(dummy_apb_pclk, NULL, "apb_pclk"), @@ -537,7 +520,7 @@ static struct clk_lookup u8500_ed_clks[] = { CLK(ssp0_ed, "ssp0", NULL), /* Peripheral Cluster #5 */ - CLK(usb_ed, "musb_hdrc.0", "usb"), + CLK(usb_ed, "musb-ux500.0", "usb"), /* Peripheral Cluster #6 */ CLK(dmc_ed, "dmc", NULL), @@ -554,7 +537,7 @@ static struct clk_lookup u8500_ed_clks[] = { static struct clk_lookup u8500_v1_clks[] = { /* Peripheral Cluster #1 */ - CLK(i2c4, "nmk-i2c.4", NULL), + CLK(i2c4, "nmk-i2c.4", NULL), CLK(spi3_v1, "spi3", NULL), CLK(msp1_v1, "msp1", NULL), @@ -578,7 +561,7 @@ static struct clk_lookup u8500_v1_clks[] = { CLK(ssp0_v1, "ssp0", NULL), /* Peripheral Cluster #5 */ - CLK(usb_v1, "musb_hdrc.0", "usb"), + CLK(usb_v1, "musb-ux500.0", "usb"), /* Peripheral Cluster #6 */ CLK(mtu1_v1, "mtu1", NULL), @@ -599,6 +582,183 @@ static struct clk_lookup u8500_v1_clks[] = { CLK(uiccclk, "uicc", NULL), }; +#ifdef CONFIG_DEBUG_FS +/* + * debugfs support to trace clock tree hierarchy and attributes with + * powerdebug + */ +static struct dentry *clk_debugfs_root; + +void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num) +{ + while (num--) { + /* Check that the clock has not been already registered */ + if (!(cl->clk->list.prev != cl->clk->list.next)) + list_add_tail(&cl->clk->list, &clk_list); + + cl++; + } +} + +static ssize_t usecount_dbg_read(struct file *file, char __user *buf, + size_t size, loff_t *off) +{ + struct clk *clk = file->f_dentry->d_inode->i_private; + char cusecount[128]; + unsigned int len; + + len = sprintf(cusecount, "%u\n", clk->enabled); + return simple_read_from_buffer(buf, size, off, cusecount, len); +} + +static ssize_t rate_dbg_read(struct file *file, char __user *buf, + size_t size, loff_t *off) +{ + struct clk *clk = file->f_dentry->d_inode->i_private; + char crate[128]; + unsigned int rate; + unsigned int len; + + rate = clk_get_rate(clk); + len = sprintf(crate, "%u\n", rate); + return simple_read_from_buffer(buf, size, off, crate, len); +} + +static const struct file_operations usecount_fops = { + .read = usecount_dbg_read, +}; + +static const struct file_operations set_rate_fops = { + .read = rate_dbg_read, +}; + +static struct dentry *clk_debugfs_register_dir(struct clk *c, + struct dentry *p_dentry) +{ + struct dentry *d, *clk_d, *child, *child_tmp; + char s[255]; + char *p = s; + + if (c->name == NULL) + p += sprintf(p, "BUG"); + else + p += sprintf(p, "%s", c->name); + + clk_d = debugfs_create_dir(s, p_dentry); + if (!clk_d) + return NULL; + + d = debugfs_create_file("usecount", S_IRUGO, + clk_d, c, &usecount_fops); + if (!d) + goto err_out; + d = debugfs_create_file("rate", S_IRUGO, + clk_d, c, &set_rate_fops); + if (!d) + goto err_out; + /* + * TODO : not currently available in ux500 + * d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags); + * if (!d) + * goto err_out; + */ + + return clk_d; + +err_out: + d = clk_d; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(clk_d); + return NULL; +} + +static void clk_debugfs_remove_dir(struct dentry *cdentry) +{ + struct dentry *d, *child, *child_tmp; + + d = cdentry; + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(cdentry); + return ; +} + +static int clk_debugfs_register_one(struct clk *c) +{ + struct clk *pa = c->parent_periph; + struct clk *bpa = c->parent_cluster; + + if (!(bpa && !pa)) { + c->dent = clk_debugfs_register_dir(c, + pa ? pa->dent : clk_debugfs_root); + if (!c->dent) + return -ENOMEM; + } + + if (bpa) { + c->dent_bus = clk_debugfs_register_dir(c, + bpa->dent_bus ? bpa->dent_bus : bpa->dent); + if ((!c->dent_bus) && (c->dent)) { + clk_debugfs_remove_dir(c->dent); + c->dent = NULL; + return -ENOMEM; + } + } + return 0; +} + +static int clk_debugfs_register(struct clk *c) +{ + int err; + struct clk *pa = c->parent_periph; + struct clk *bpa = c->parent_cluster; + + if (pa && (!pa->dent && !pa->dent_bus)) { + err = clk_debugfs_register(pa); + if (err) + return err; + } + + if (bpa && (!bpa->dent && !bpa->dent_bus)) { + err = clk_debugfs_register(bpa); + if (err) + return err; + } + + if ((!c->dent) && (!c->dent_bus)) { + err = clk_debugfs_register_one(c); + if (err) + return err; + } + return 0; +} + +static int __init clk_debugfs_init(void) +{ + struct clk *c; + struct dentry *d; + int err; + + d = debugfs_create_dir("clock", NULL); + if (!d) + return -ENOMEM; + clk_debugfs_root = d; + + list_for_each_entry(c, &clk_list, list) { + err = clk_debugfs_register(c); + if (err) + goto err_out; + } + return 0; +err_out: + debugfs_remove_recursive(clk_debugfs_root); + return err; +} + +late_initcall(clk_debugfs_init); +#endif /* defined(CONFIG_DEBUG_FS) */ + int __init clk_init(void) { if (cpu_is_u8500ed()) { @@ -609,7 +769,8 @@ int __init clk_init(void) /* Clock tree for U5500 not implemented yet */ clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; - clk_per6clk.rate = 26000000; + clk_uartclk.rate = 36360000; + clk_sdmmcclk.rate = 99900000; } clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); @@ -618,5 +779,12 @@ int __init clk_init(void) else clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); +#ifdef CONFIG_DEBUG_FS + clk_debugfs_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); + if (cpu_is_u8500ed()) + clk_debugfs_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks)); + else + clk_debugfs_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); +#endif return 0; } diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h index a05802501527..074490705229 100644 --- a/arch/arm/mach-ux500/clock.h +++ b/arch/arm/mach-ux500/clock.h @@ -90,6 +90,10 @@ struct clk { struct clk *parent_cluster; struct clk *parent_periph; +#if defined(CONFIG_DEBUG_FS) + struct dentry *dent; /* For visible tree hierarchy */ + struct dentry *dent_bus; /* For visible tree hierarchy */ +#endif }; #define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \ diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c index 2f87075e9d6f..c9dc2eff3cb2 100644 --- a/arch/arm/mach-ux500/cpu-db5500.c +++ b/arch/arm/mach-ux500/cpu-db5500.c @@ -8,15 +8,36 @@ #include <linux/platform_device.h> #include <linux/amba/bus.h> #include <linux/io.h> +#include <linux/irq.h> #include <asm/mach/map.h> +#include <asm/pmu.h> + +#include <plat/gpio.h> #include <mach/hardware.h> #include <mach/devices.h> #include <mach/setup.h> #include <mach/irqs.h> +#include <mach/usb.h> + +#include "devices-db5500.h" +#include "ste-dma40-db5500.h" + +static struct map_desc u5500_uart_io_desc[] __initdata = { + __IO_DEV_DESC(U5500_UART0_BASE, SZ_4K), + __IO_DEV_DESC(U5500_UART2_BASE, SZ_4K), +}; static struct map_desc u5500_io_desc[] __initdata = { + __IO_DEV_DESC(U5500_GIC_CPU_BASE, SZ_4K), + __IO_DEV_DESC(U5500_GIC_DIST_BASE, SZ_4K), + __IO_DEV_DESC(U5500_L2CC_BASE, SZ_4K), + __IO_DEV_DESC(U5500_TWD_BASE, SZ_4K), + __IO_DEV_DESC(U5500_MTU0_BASE, SZ_4K), + __IO_DEV_DESC(U5500_SCU_BASE, SZ_4K), + __IO_DEV_DESC(U5500_BACKUPRAM0_BASE, SZ_8K), + __IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO2_BASE, SZ_4K), @@ -25,6 +46,26 @@ static struct map_desc u5500_io_desc[] __initdata = { __IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K), }; +static struct resource db5500_pmu_resources[] = { + [0] = { + .start = IRQ_DB5500_PMU0, + .end = IRQ_DB5500_PMU0, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = IRQ_DB5500_PMU1, + .end = IRQ_DB5500_PMU1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device db5500_pmu_device = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = ARRAY_SIZE(db5500_pmu_resources), + .resource = db5500_pmu_resources, +}; + static struct resource mbox0_resources[] = { { .name = "mbox_peer", @@ -109,31 +150,75 @@ static struct platform_device mbox2_device = { .num_resources = ARRAY_SIZE(mbox2_resources), }; -static struct platform_device *u5500_platform_devs[] __initdata = { - &u5500_gpio_devs[0], - &u5500_gpio_devs[1], - &u5500_gpio_devs[2], - &u5500_gpio_devs[3], - &u5500_gpio_devs[4], - &u5500_gpio_devs[5], - &u5500_gpio_devs[6], - &u5500_gpio_devs[7], +static struct platform_device *db5500_platform_devs[] __initdata = { + &db5500_pmu_device, &mbox0_device, &mbox1_device, &mbox2_device, }; +static resource_size_t __initdata db5500_gpio_base[] = { + U5500_GPIOBANK0_BASE, + U5500_GPIOBANK1_BASE, + U5500_GPIOBANK2_BASE, + U5500_GPIOBANK3_BASE, + U5500_GPIOBANK4_BASE, + U5500_GPIOBANK5_BASE, + U5500_GPIOBANK6_BASE, + U5500_GPIOBANK7_BASE, +}; + +static void __init db5500_add_gpios(void) +{ + struct nmk_gpio_platform_data pdata = { + /* No custom data yet */ + }; + + dbx500_add_gpios(ARRAY_AND_SIZE(db5500_gpio_base), + IRQ_DB5500_GPIO0, &pdata); +} + void __init u5500_map_io(void) { + /* + * Map the UARTs early so that the DEBUG_LL stuff continues to work. + */ + iotable_init(u5500_uart_io_desc, ARRAY_SIZE(u5500_uart_io_desc)); + ux500_map_io(); iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc)); } +static int usb_db5500_rx_dma_cfg[] = { + DB5500_DMA_DEV4_USB_OTG_IEP_1_9, + DB5500_DMA_DEV5_USB_OTG_IEP_2_10, + DB5500_DMA_DEV6_USB_OTG_IEP_3_11, + DB5500_DMA_DEV20_USB_OTG_IEP_4_12, + DB5500_DMA_DEV21_USB_OTG_IEP_5_13, + DB5500_DMA_DEV22_USB_OTG_IEP_6_14, + DB5500_DMA_DEV23_USB_OTG_IEP_7_15, + DB5500_DMA_DEV38_USB_OTG_IEP_8 +}; + +static int usb_db5500_tx_dma_cfg[] = { + DB5500_DMA_DEV4_USB_OTG_OEP_1_9, + DB5500_DMA_DEV5_USB_OTG_OEP_2_10, + DB5500_DMA_DEV6_USB_OTG_OEP_3_11, + DB5500_DMA_DEV20_USB_OTG_OEP_4_12, + DB5500_DMA_DEV21_USB_OTG_OEP_5_13, + DB5500_DMA_DEV22_USB_OTG_OEP_6_14, + DB5500_DMA_DEV23_USB_OTG_OEP_7_15, + DB5500_DMA_DEV38_USB_OTG_OEP_8 +}; + void __init u5500_init_devices(void) { - ux500_init_devices(); + db5500_add_gpios(); + db5500_dma_init(); + db5500_add_rtc(); + db5500_add_usb(usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg); - platform_add_devices(u5500_platform_devs, - ARRAY_SIZE(u5500_platform_devs)); + platform_add_devices(db5500_platform_devs, + ARRAY_SIZE(db5500_platform_devs)); } diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 4acab7544b3c..516126cb357d 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -12,152 +12,185 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/amba/bus.h> +#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/io.h> #include <asm/mach/map.h> +#include <asm/pmu.h> #include <mach/hardware.h> #include <mach/setup.h> #include <mach/devices.h> +#include <mach/usb.h> -static struct platform_device *platform_devs[] __initdata = { - &u8500_gpio_devs[0], - &u8500_gpio_devs[1], - &u8500_gpio_devs[2], - &u8500_gpio_devs[3], - &u8500_gpio_devs[4], - &u8500_gpio_devs[5], - &u8500_gpio_devs[6], - &u8500_gpio_devs[7], - &u8500_gpio_devs[8], - &u8500_dma40_device, -}; +#include "devices-db8500.h" +#include "ste-dma40-db8500.h" /* minimum static i/o mapping required to boot U8500 platforms */ +static struct map_desc u8500_uart_io_desc[] __initdata = { + __IO_DEV_DESC(U8500_UART0_BASE, SZ_4K), + __IO_DEV_DESC(U8500_UART2_BASE, SZ_4K), +}; + static struct map_desc u8500_io_desc[] __initdata = { + __IO_DEV_DESC(U8500_GIC_CPU_BASE, SZ_4K), + __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K), + __IO_DEV_DESC(U8500_L2CC_BASE, SZ_4K), + __IO_DEV_DESC(U8500_TWD_BASE, SZ_4K), + __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), + __IO_DEV_DESC(U8500_SCU_BASE, SZ_4K), + __IO_DEV_DESC(U8500_BACKUPRAM0_BASE, SZ_8K), + + __IO_DEV_DESC(U8500_CLKRST1_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST2_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST3_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K), + __IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K), + __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), - __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K), - __MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M), }; -static struct map_desc u8500ed_io_desc[] __initdata = { +static struct map_desc u8500_ed_io_desc[] __initdata = { __IO_DEV_DESC(U8500_MTU0_BASE_ED, SZ_4K), __IO_DEV_DESC(U8500_CLKRST7_BASE_ED, SZ_8K), }; -static struct map_desc u8500v1_io_desc[] __initdata = { +static struct map_desc u8500_v1_io_desc[] __initdata = { __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), + __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE_V1, SZ_4K), }; -/* - * Functions to differentiate between later ASICs - * We look into the end of the ROM to locate the hardcoded ASIC ID. - * This is only needed to differentiate between minor revisions and - * process variants of an ASIC, the major revisions are encoded in - * the cpuid. - */ -#define U8500_ASIC_ID_LOC_ED_V1 (U8500_BOOT_ROM_BASE + 0x1FFF4) -#define U8500_ASIC_ID_LOC_V2 (U8500_BOOT_ROM_BASE + 0x1DBF4) -#define U8500_ASIC_REV_ED 0x01 -#define U8500_ASIC_REV_V10 0xA0 -#define U8500_ASIC_REV_V11 0xA1 -#define U8500_ASIC_REV_V20 0xB0 - -/** - * struct db8500_asic_id - fields of the ASIC ID - * @process: the manufacturing process, 0x40 is 40 nm - * 0x00 is "standard" - * @partnumber: hithereto 0x8500 for DB8500 - * @revision: version code in the series - * This field definion is not formally defined but makes - * sense. - */ -struct db8500_asic_id { - u8 process; - u16 partnumber; - u8 revision; +static struct map_desc u8500_v2_io_desc[] __initdata = { + __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K), }; -/* This isn't going to change at runtime */ -static struct db8500_asic_id db8500_id; - -static void __init get_db8500_asic_id(void) +void __init u8500_map_io(void) { - u32 asicid; + /* + * Map the UARTs early so that the DEBUG_LL stuff continues to work. + */ + iotable_init(u8500_uart_io_desc, ARRAY_SIZE(u8500_uart_io_desc)); - if (cpu_is_u8500v1() || cpu_is_u8500ed()) - asicid = readl(__io_address(U8500_ASIC_ID_LOC_ED_V1)); - else if (cpu_is_u8500v2()) - asicid = readl(__io_address(U8500_ASIC_ID_LOC_V2)); - else - BUG(); + ux500_map_io(); - db8500_id.process = (asicid >> 24); - db8500_id.partnumber = (asicid >> 16) & 0xFFFFU; - db8500_id.revision = asicid & 0xFFU; -} + iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); -bool cpu_is_u8500v10(void) -{ - return (db8500_id.revision == U8500_ASIC_REV_V10); + if (cpu_is_u8500ed()) + iotable_init(u8500_ed_io_desc, ARRAY_SIZE(u8500_ed_io_desc)); + else if (cpu_is_u8500v1()) + iotable_init(u8500_v1_io_desc, ARRAY_SIZE(u8500_v1_io_desc)); + else if (cpu_is_u8500v2()) + iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc)); } -bool cpu_is_u8500v11(void) -{ - return (db8500_id.revision == U8500_ASIC_REV_V11); -} +static struct resource db8500_pmu_resources[] = { + [0] = { + .start = IRQ_DB8500_PMU, + .end = IRQ_DB8500_PMU, + .flags = IORESOURCE_IRQ, + }, +}; -bool cpu_is_u8500v20(void) +/* + * The PMU IRQ lines of two cores are wired together into a single interrupt. + * Bounce the interrupt to the other core if it's not ours. + */ +static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler) { - return (db8500_id.revision == U8500_ASIC_REV_V20); + irqreturn_t ret = handler(irq, dev); + int other = !smp_processor_id(); + + if (ret == IRQ_NONE && cpu_online(other)) + irq_set_affinity(irq, cpumask_of(other)); + + /* + * We should be able to get away with the amount of IRQ_NONEs we give, + * while still having the spurious IRQ detection code kick in if the + * interrupt really starts hitting spuriously. + */ + return ret; } -void __init u8500_map_io(void) -{ - ux500_map_io(); +static struct arm_pmu_platdata db8500_pmu_platdata = { + .handle_irq = db8500_pmu_handler, +}; - iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); +static struct platform_device db8500_pmu_device = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = ARRAY_SIZE(db8500_pmu_resources), + .resource = db8500_pmu_resources, + .dev.platform_data = &db8500_pmu_platdata, +}; - if (cpu_is_u8500ed()) - iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc)); - else - iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc)); +static struct platform_device *platform_devs[] __initdata = { + &u8500_dma40_device, + &db8500_pmu_device, +}; + +static resource_size_t __initdata db8500_gpio_base[] = { + U8500_GPIOBANK0_BASE, + U8500_GPIOBANK1_BASE, + U8500_GPIOBANK2_BASE, + U8500_GPIOBANK3_BASE, + U8500_GPIOBANK4_BASE, + U8500_GPIOBANK5_BASE, + U8500_GPIOBANK6_BASE, + U8500_GPIOBANK7_BASE, + U8500_GPIOBANK8_BASE, +}; - /* Read out the ASIC ID as early as we can */ - get_db8500_asic_id(); +static void __init db8500_add_gpios(void) +{ + struct nmk_gpio_platform_data pdata = { + /* No custom data yet */ + }; + + dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base), + IRQ_DB8500_GPIO0, &pdata); } +static int usb_db8500_rx_dma_cfg[] = { + DB8500_DMA_DEV38_USB_OTG_IEP_1_9, + DB8500_DMA_DEV37_USB_OTG_IEP_2_10, + DB8500_DMA_DEV36_USB_OTG_IEP_3_11, + DB8500_DMA_DEV19_USB_OTG_IEP_4_12, + DB8500_DMA_DEV18_USB_OTG_IEP_5_13, + DB8500_DMA_DEV17_USB_OTG_IEP_6_14, + DB8500_DMA_DEV16_USB_OTG_IEP_7_15, + DB8500_DMA_DEV39_USB_OTG_IEP_8 +}; + +static int usb_db8500_tx_dma_cfg[] = { + DB8500_DMA_DEV38_USB_OTG_OEP_1_9, + DB8500_DMA_DEV37_USB_OTG_OEP_2_10, + DB8500_DMA_DEV36_USB_OTG_OEP_3_11, + DB8500_DMA_DEV19_USB_OTG_OEP_4_12, + DB8500_DMA_DEV18_USB_OTG_OEP_5_13, + DB8500_DMA_DEV17_USB_OTG_OEP_6_14, + DB8500_DMA_DEV16_USB_OTG_OEP_7_15, + DB8500_DMA_DEV39_USB_OTG_OEP_8 +}; + /* * This function is called from the board init */ void __init u8500_init_devices(void) { - /* Display some ASIC boilerplate */ - pr_info("DB8500: process: %02x, revision ID: 0x%02x\n", - db8500_id.process, db8500_id.revision); - if (cpu_is_u8500ed()) - pr_info("DB8500: Early Drop (ED)\n"); - else if (cpu_is_u8500v10()) - pr_info("DB8500: version 1.0\n"); - else if (cpu_is_u8500v11()) - pr_info("DB8500: version 1.1\n"); - else if (cpu_is_u8500v20()) - pr_info("DB8500: version 2.0\n"); - else - pr_warning("ASIC: UNKNOWN SILICON VERSION!\n"); - - ux500_init_devices(); - if (cpu_is_u8500ed()) dma40_u8500ed_fixup(); - /* Register the platform devices */ + db8500_add_rtc(); + db8500_add_gpios(); + db8500_add_usb(usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); + + platform_device_register_simple("cpufreq-u8500", -1, NULL, 0); platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); return ; diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index 608a1372b172..5a43107c6232 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -6,7 +6,6 @@ */ #include <linux/platform_device.h> -#include <linux/amba/bus.h> #include <linux/io.h> #include <linux/clk.h> @@ -20,54 +19,36 @@ #include <mach/hardware.h> #include <mach/setup.h> #include <mach/devices.h> +#include <mach/prcmu.h> #include "clock.h" -static struct map_desc ux500_io_desc[] __initdata = { - __IO_DEV_DESC(UX500_UART0_BASE, SZ_4K), - __IO_DEV_DESC(UX500_UART2_BASE, SZ_4K), - - __IO_DEV_DESC(UX500_GIC_CPU_BASE, SZ_4K), - __IO_DEV_DESC(UX500_GIC_DIST_BASE, SZ_4K), - __IO_DEV_DESC(UX500_L2CC_BASE, SZ_4K), - __IO_DEV_DESC(UX500_TWD_BASE, SZ_4K), - __IO_DEV_DESC(UX500_SCU_BASE, SZ_4K), - - __IO_DEV_DESC(UX500_CLKRST1_BASE, SZ_4K), - __IO_DEV_DESC(UX500_CLKRST2_BASE, SZ_4K), - __IO_DEV_DESC(UX500_CLKRST3_BASE, SZ_4K), - __IO_DEV_DESC(UX500_CLKRST5_BASE, SZ_4K), - __IO_DEV_DESC(UX500_CLKRST6_BASE, SZ_4K), - - __IO_DEV_DESC(UX500_MTU0_BASE, SZ_4K), - __IO_DEV_DESC(UX500_MTU1_BASE, SZ_4K), - - __IO_DEV_DESC(UX500_BACKUPRAM0_BASE, SZ_8K), -}; - -static struct amba_device *ux500_amba_devs[] __initdata = { - &ux500_pl031_device, -}; +#ifdef CONFIG_CACHE_L2X0 +static void __iomem *l2x0_base; +#endif -void __init ux500_map_io(void) +void __init ux500_init_irq(void) { - iotable_init(ux500_io_desc, ARRAY_SIZE(ux500_io_desc)); -} + void __iomem *dist_base; + void __iomem *cpu_base; -void __init ux500_init_devices(void) -{ - amba_add_devices(ux500_amba_devs, ARRAY_SIZE(ux500_amba_devs)); -} + if (cpu_is_u5500()) { + dist_base = __io_address(U5500_GIC_DIST_BASE); + cpu_base = __io_address(U5500_GIC_CPU_BASE); + } else if (cpu_is_u8500()) { + dist_base = __io_address(U8500_GIC_DIST_BASE); + cpu_base = __io_address(U8500_GIC_CPU_BASE); + } else + ux500_unknown_soc(); -void __init ux500_init_irq(void) -{ - gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29); - gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE)); + gic_init(0, 29, dist_base, cpu_base); /* * Init clocks here so that they are available for system timer * initialization. */ + if (cpu_is_u8500()) + prcmu_early_init(); clk_init(); } @@ -81,7 +62,8 @@ static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask) static inline void ux500_cache_sync(void) { - void __iomem *base = __io_address(UX500_L2CC_BASE); + void __iomem *base = l2x0_base; + writel_relaxed(0, base + L2X0_CACHE_SYNC); ux500_cache_wait(base + L2X0_CACHE_SYNC, 1); } @@ -103,20 +85,23 @@ static void ux500_l2x0_disable(void) */ static void ux500_l2x0_inv_all(void) { - void __iomem *l2x0_base = __io_address(UX500_L2CC_BASE); + void __iomem *base = l2x0_base; uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */ /* invalidate all ways */ - writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); - ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); + writel_relaxed(l2x0_way_mask, base + L2X0_INV_WAY); + ux500_cache_wait(base + L2X0_INV_WAY, l2x0_way_mask); ux500_cache_sync(); } static int ux500_l2x0_init(void) { - void __iomem *l2x0_base; - - l2x0_base = __io_address(UX500_L2CC_BASE); + if (cpu_is_u5500()) + l2x0_base = __io_address(U5500_L2CC_BASE); + else if (cpu_is_u8500()) + l2x0_base = __io_address(U8500_L2CC_BASE); + else + ux500_unknown_soc(); /* 64KB way size, 8 way associativity, force WA */ l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); @@ -134,13 +119,21 @@ static void __init ux500_timer_init(void) { #ifdef CONFIG_LOCAL_TIMERS /* Setup the local timer base */ - twd_base = __io_address(UX500_TWD_BASE); + if (cpu_is_u5500()) + twd_base = __io_address(U5500_TWD_BASE); + else if (cpu_is_u8500()) + twd_base = __io_address(U8500_TWD_BASE); + else + ux500_unknown_soc(); #endif - /* Setup the MTU base */ - if (cpu_is_u8500ed()) + if (cpu_is_u5500()) + mtu_base = __io_address(U5500_MTU0_BASE); + else if (cpu_is_u8500ed()) mtu_base = __io_address(U8500_MTU0_BASE_ED); + else if (cpu_is_u8500()) + mtu_base = __io_address(U8500_MTU0_BASE); else - mtu_base = __io_address(UX500_MTU0_BASE); + ux500_unknown_soc(); nmdk_timer_init(); } diff --git a/arch/arm/mach-ux500/cpufreq.c b/arch/arm/mach-ux500/cpufreq.c new file mode 100644 index 000000000000..5c5b747f134d --- /dev/null +++ b/arch/arm/mach-ux500/cpufreq.c @@ -0,0 +1,211 @@ +/* + * CPU frequency scaling for u8500 + * Inspired by linux/arch/arm/mach-davinci/cpufreq.c + * + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * Author: Martin Persson <martin.persson@stericsson.com> + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> + * + */ + +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <mach/prcmu.h> +#include <mach/prcmu-defs.h> + +#define DRIVER_NAME "cpufreq-u8500" +#define CPUFREQ_NAME "u8500" + +static struct device *dev; + +static struct cpufreq_frequency_table freq_table[] = { + [0] = { + .index = 0, + .frequency = 200000, + }, + [1] = { + .index = 1, + .frequency = 300000, + }, + [2] = { + .index = 2, + .frequency = 600000, + }, + [3] = { + /* Used for CPU_OPP_MAX, if available */ + .index = 3, + .frequency = CPUFREQ_TABLE_END, + }, + [4] = { + .index = 4, + .frequency = CPUFREQ_TABLE_END, + }, +}; + +static enum prcmu_cpu_opp index2opp[] = { + CPU_OPP_EXT_CLK, + CPU_OPP_50, + CPU_OPP_100, + CPU_OPP_MAX +}; + +static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static int u8500_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned int index; + int ret = 0; + + /* + * Ensure desired rate is within allowed range. Some govenors + * (ondemand) will just pass target_freq=0 to get the minimum. + */ + if (target_freq < policy->cpuinfo.min_freq) + target_freq = policy->cpuinfo.min_freq; + if (target_freq > policy->cpuinfo.max_freq) + target_freq = policy->cpuinfo.max_freq; + + ret = cpufreq_frequency_table_target(policy, freq_table, + target_freq, relation, &index); + if (ret < 0) { + dev_err(dev, "Could not look up next frequency\n"); + return ret; + } + + freqs.old = policy->cur; + freqs.new = freq_table[index].frequency; + freqs.cpu = policy->cpu; + + if (freqs.old == freqs.new) { + dev_dbg(dev, "Current and target frequencies are equal\n"); + return 0; + } + + dev_dbg(dev, "transition: %u --> %u\n", freqs.old, freqs.new); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + ret = prcmu_set_cpu_opp(index2opp[index]); + if (ret < 0) { + dev_err(dev, "Failed to set OPP level\n"); + return ret; + } + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return ret; +} + +static unsigned int u8500_cpufreq_getspeed(unsigned int cpu) +{ + int i; + + for (i = 0; prcmu_get_cpu_opp() != index2opp[i]; i++) + ; + return freq_table[i].frequency; +} + +static int __cpuinit u8500_cpu_init(struct cpufreq_policy *policy) +{ + int res; + + BUILD_BUG_ON(ARRAY_SIZE(index2opp) + 1 != ARRAY_SIZE(freq_table)); + + if (cpu_is_u8500v2()) { + freq_table[1].frequency = 400000; + freq_table[2].frequency = 800000; + if (prcmu_has_arm_maxopp()) + freq_table[3].frequency = 1000000; + } + + /* get policy fields based on the table */ + res = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (!res) + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); + else { + dev_err(dev, "u8500-cpufreq : Failed to read policy table\n"); + return res; + } + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + policy->cur = u8500_cpufreq_getspeed(policy->cpu); + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + + /* + * FIXME : Need to take time measurement across the target() + * function with no/some/all drivers in the notification + * list. + */ + policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */ + + /* policy sharing between dual CPUs */ + cpumask_copy(policy->cpus, &cpu_present_map); + + policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; + + return res; +} + +static struct freq_attr *u8500_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; +static int u8500_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static struct cpufreq_driver u8500_driver = { + .owner = THIS_MODULE, + .flags = CPUFREQ_STICKY, + .verify = u8500_cpufreq_verify_speed, + .target = u8500_cpufreq_target, + .get = u8500_cpufreq_getspeed, + .init = u8500_cpu_init, + .exit = u8500_cpu_exit, + .name = CPUFREQ_NAME, + .attr = u8500_cpufreq_attr, +}; + +static int __init u8500_cpufreq_probe(struct platform_device *pdev) +{ + dev = &pdev->dev; + return cpufreq_register_driver(&u8500_driver); +} + +static int __exit u8500_cpufreq_remove(struct platform_device *pdev) +{ + return cpufreq_unregister_driver(&u8500_driver); +} + +static struct platform_driver u8500_cpufreq_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .remove = __exit_p(u8500_cpufreq_remove), +}; + +static int __init u8500_cpufreq_init(void) +{ + return platform_driver_probe(&u8500_cpufreq_driver, + &u8500_cpufreq_probe); +} + +device_initcall(u8500_cpufreq_init); diff --git a/arch/arm/mach-ux500/devices-common.c b/arch/arm/mach-ux500/devices-common.c new file mode 100644 index 000000000000..13a4ce046ae5 --- /dev/null +++ b/arch/arm/mach-ux500/devices-common.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/amba/bus.h> + +#include <plat/gpio.h> + +#include <mach/hardware.h> + +#include "devices-common.h" + +struct amba_device * +dbx500_add_amba_device(const char *name, resource_size_t base, + int irq, void *pdata, unsigned int periphid) +{ + struct amba_device *dev; + int ret; + + dev = kzalloc(sizeof *dev, GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->dev.init_name = name; + + dev->res.start = base; + dev->res.end = base + SZ_4K - 1; + dev->res.flags = IORESOURCE_MEM; + + dev->dma_mask = DMA_BIT_MASK(32); + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + dev->irq[0] = irq; + dev->irq[1] = NO_IRQ; + + dev->periphid = periphid; + + dev->dev.platform_data = pdata; + + ret = amba_device_register(dev, &iomem_resource); + if (ret) { + kfree(dev); + return ERR_PTR(ret); + } + + return dev; +} + +static struct platform_device * +dbx500_add_platform_device(const char *name, int id, void *pdata, + struct resource *res, int resnum) +{ + struct platform_device *dev; + int ret; + + dev = platform_device_alloc(name, id); + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; + + ret = platform_device_add_resources(dev, res, resnum); + if (ret) + goto out_free; + + dev->dev.platform_data = pdata; + + ret = platform_device_add(dev); + if (ret) + goto out_free; + + return dev; + +out_free: + platform_device_put(dev); + return ERR_PTR(ret); +} + +struct platform_device * +dbx500_add_platform_device_4k1irq(const char *name, int id, + resource_size_t base, + int irq, void *pdata) +{ + struct resource resources[] = { + [0] = { + .start = base, + .end = base + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = irq, + .end = irq, + .flags = IORESOURCE_IRQ, + } + }; + + return dbx500_add_platform_device(name, id, pdata, resources, + ARRAY_SIZE(resources)); +} + +static struct platform_device * +dbx500_add_gpio(int id, resource_size_t addr, int irq, + struct nmk_gpio_platform_data *pdata) +{ + struct resource resources[] = { + { + .start = addr, + .end = addr + 127, + .flags = IORESOURCE_MEM, + }, + { + .start = irq, + .end = irq, + .flags = IORESOURCE_IRQ, + } + }; + + return platform_device_register_resndata(NULL, "gpio", id, + resources, ARRAY_SIZE(resources), + pdata, sizeof(*pdata)); +} + +void dbx500_add_gpios(resource_size_t *base, int num, int irq, + struct nmk_gpio_platform_data *pdata) +{ + int first = 0; + int i; + + for (i = 0; i < num; i++, first += 32, irq++) { + pdata->first_gpio = first; + pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first); + pdata->num_gpio = 32; + + dbx500_add_gpio(i, base[i], irq, pdata); + } +} diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h new file mode 100644 index 000000000000..c719b5a1d913 --- /dev/null +++ b/arch/arm/mach-ux500/devices-common.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __DEVICES_COMMON_H +#define __DEVICES_COMMON_H + +extern struct amba_device * +dbx500_add_amba_device(const char *name, resource_size_t base, + int irq, void *pdata, unsigned int periphid); + +extern struct platform_device * +dbx500_add_platform_device_4k1irq(const char *name, int id, + resource_size_t base, + int irq, void *pdata); + +struct spi_master_cntlr; + +static inline struct amba_device * +dbx500_add_msp_spi(const char *name, resource_size_t base, int irq, + struct spi_master_cntlr *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, 0); +} + +static inline struct amba_device * +dbx500_add_spi(const char *name, resource_size_t base, int irq, + struct spi_master_cntlr *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, 0); +} + +struct mmci_platform_data; + +static inline struct amba_device * +dbx500_add_sdi(const char *name, resource_size_t base, int irq, + struct mmci_platform_data *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, 0); +} + +struct amba_pl011_data; + +static inline struct amba_device * +dbx500_add_uart(const char *name, resource_size_t base, int irq, + struct amba_pl011_data *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, 0); +} + +struct nmk_i2c_controller; + +static inline struct platform_device * +dbx500_add_i2c(int id, resource_size_t base, int irq, + struct nmk_i2c_controller *pdata) +{ + return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq, + pdata); +} + +struct msp_i2s_platform_data; + +static inline struct platform_device * +dbx500_add_msp_i2s(int id, resource_size_t base, int irq, + struct msp_i2s_platform_data *pdata) +{ + return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq, + pdata); +} + +static inline struct amba_device * +dbx500_add_rtc(resource_size_t base, int irq) +{ + return dbx500_add_amba_device("rtc-pl031", base, irq, NULL, 0); +} + +struct nmk_gpio_platform_data; + +void dbx500_add_gpios(resource_size_t *base, int num, int irq, + struct nmk_gpio_platform_data *pdata); + +#endif diff --git a/arch/arm/mach-ux500/devices-db5500.c b/arch/arm/mach-ux500/devices-db5500.c deleted file mode 100644 index 33e5b56bebb6..000000000000 --- a/arch/arm/mach-ux500/devices-db5500.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson - * License terms: GNU General Public License (GPL) version 2 - */ - -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/gpio.h> - -#include <mach/hardware.h> -#include <mach/devices.h> - -static struct nmk_gpio_platform_data u5500_gpio_data[] = { - GPIO_DATA("GPIO-0-31", 0), - GPIO_DATA("GPIO-32-63", 32), /* 36..63 not routed to pin */ - GPIO_DATA("GPIO-64-95", 64), /* 83..95 not routed to pin */ - GPIO_DATA("GPIO-96-127", 96), /* 102..127 not routed to pin */ - GPIO_DATA("GPIO-128-159", 128), /* 149..159 not routed to pin */ - GPIO_DATA("GPIO-160-191", 160), - GPIO_DATA("GPIO-192-223", 192), - GPIO_DATA("GPIO-224-255", 224), /* 228..255 not routed to pin */ -}; - -static struct resource u5500_gpio_resources[] = { - GPIO_RESOURCE(0), - GPIO_RESOURCE(1), - GPIO_RESOURCE(2), - GPIO_RESOURCE(3), - GPIO_RESOURCE(4), - GPIO_RESOURCE(5), - GPIO_RESOURCE(6), - GPIO_RESOURCE(7), -}; - -struct platform_device u5500_gpio_devs[] = { - GPIO_DEVICE(0), - GPIO_DEVICE(1), - GPIO_DEVICE(2), - GPIO_DEVICE(3), - GPIO_DEVICE(4), - GPIO_DEVICE(5), - GPIO_DEVICE(6), - GPIO_DEVICE(7), -}; diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h new file mode 100644 index 000000000000..94627f7783b0 --- /dev/null +++ b/arch/arm/mach-ux500/devices-db5500.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __DEVICES_DB5500_H +#define __DEVICES_DB5500_H + +#include "devices-common.h" + +#define db5500_add_i2c1(pdata) \ + dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata) +#define db5500_add_i2c2(pdata) \ + dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata) +#define db5500_add_i2c3(pdata) \ + dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata) + +#define db5500_add_msp0_i2s(pdata) \ + dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata) +#define db5500_add_msp1_i2s(pdata) \ + dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata) +#define db5500_add_msp2_i2s(pdata) \ + dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata) + +#define db5500_add_msp0_spi(pdata) \ + dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata) +#define db5500_add_msp1_spi(pdata) \ + dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata) +#define db5500_add_msp2_spi(pdata) \ + dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata) + +#define db5500_add_rtc() \ + dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC); + +#define db5500_add_usb(rx_cfg, tx_cfg) \ + ux500_add_usb(U5500_USBOTG_BASE, IRQ_DB5500_USBOTG, rx_cfg, tx_cfg) + +#define db5500_add_sdi0(pdata) \ + dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata) +#define db5500_add_sdi1(pdata) \ + dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata) +#define db5500_add_sdi2(pdata) \ + dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata) +#define db5500_add_sdi3(pdata) \ + dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata) +#define db5500_add_sdi4(pdata) \ + dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata) + +#define db5500_add_spi0(pdata) \ + dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata) +#define db5500_add_spi1(pdata) \ + dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata) +#define db5500_add_spi2(pdata) \ + dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata) +#define db5500_add_spi3(pdata) \ + dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata) + +#define db5500_add_uart0(plat) \ + dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, plat) +#define db5500_add_uart1(plat) \ + dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1, plat) +#define db5500_add_uart2(plat) \ + dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2, plat) +#define db5500_add_uart3(plat) \ + dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3, plat) + +#endif diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c index 4a94be3304b9..73b17404b194 100644 --- a/arch/arm/mach-ux500/devices-db8500.c +++ b/arch/arm/mach-ux500/devices-db8500.c @@ -11,6 +11,7 @@ #include <linux/io.h> #include <linux/gpio.h> #include <linux/amba/bus.h> +#include <linux/amba/pl022.h> #include <plat/ste_dma40.h> @@ -19,173 +20,6 @@ #include "ste-dma40-db8500.h" -static struct nmk_gpio_platform_data u8500_gpio_data[] = { - GPIO_DATA("GPIO-0-31", 0), - GPIO_DATA("GPIO-32-63", 32), /* 37..63 not routed to pin */ - GPIO_DATA("GPIO-64-95", 64), - GPIO_DATA("GPIO-96-127", 96), /* 98..127 not routed to pin */ - GPIO_DATA("GPIO-128-159", 128), - GPIO_DATA("GPIO-160-191", 160), /* 172..191 not routed to pin */ - GPIO_DATA("GPIO-192-223", 192), - GPIO_DATA("GPIO-224-255", 224), /* 231..255 not routed to pin */ - GPIO_DATA("GPIO-256-288", 256), /* 268..288 not routed to pin */ -}; - -static struct resource u8500_gpio_resources[] = { - GPIO_RESOURCE(0), - GPIO_RESOURCE(1), - GPIO_RESOURCE(2), - GPIO_RESOURCE(3), - GPIO_RESOURCE(4), - GPIO_RESOURCE(5), - GPIO_RESOURCE(6), - GPIO_RESOURCE(7), - GPIO_RESOURCE(8), -}; - -struct platform_device u8500_gpio_devs[] = { - GPIO_DEVICE(0), - GPIO_DEVICE(1), - GPIO_DEVICE(2), - GPIO_DEVICE(3), - GPIO_DEVICE(4), - GPIO_DEVICE(5), - GPIO_DEVICE(6), - GPIO_DEVICE(7), - GPIO_DEVICE(8), -}; - -struct amba_device u8500_ssp0_device = { - .dev = { - .coherent_dma_mask = ~0, - .init_name = "ssp0", - }, - .res = { - .start = U8500_SSP0_BASE, - .end = U8500_SSP0_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = {IRQ_DB8500_SSP0, NO_IRQ }, - /* ST-Ericsson modified id */ - .periphid = SSP_PER_ID, -}; - -static struct resource u8500_i2c0_resources[] = { - [0] = { - .start = U8500_I2C0_BASE, - .end = U8500_I2C0_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_DB8500_I2C0, - .end = IRQ_DB8500_I2C0, - .flags = IORESOURCE_IRQ, - } -}; - -struct platform_device u8500_i2c0_device = { - .name = "nmk-i2c", - .id = 0, - .resource = u8500_i2c0_resources, - .num_resources = ARRAY_SIZE(u8500_i2c0_resources), -}; - -static struct resource u8500_i2c4_resources[] = { - [0] = { - .start = U8500_I2C4_BASE, - .end = U8500_I2C4_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_DB8500_I2C4, - .end = IRQ_DB8500_I2C4, - .flags = IORESOURCE_IRQ, - } -}; - -struct platform_device u8500_i2c4_device = { - .name = "nmk-i2c", - .id = 4, - .resource = u8500_i2c4_resources, - .num_resources = ARRAY_SIZE(u8500_i2c4_resources), -}; - -/* - * SD/MMC - */ - -struct amba_device u8500_sdi0_device = { - .dev = { - .init_name = "sdi0", - }, - .res = { - .start = U8500_SDI0_BASE, - .end = U8500_SDI0_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = {IRQ_DB8500_SDMMC0, NO_IRQ}, -}; - -struct amba_device u8500_sdi1_device = { - .dev = { - .init_name = "sdi1", - }, - .res = { - .start = U8500_SDI1_BASE, - .end = U8500_SDI1_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = {IRQ_DB8500_SDMMC1, NO_IRQ}, -}; - -struct amba_device u8500_sdi2_device = { - .dev = { - .init_name = "sdi2", - }, - .res = { - .start = U8500_SDI2_BASE, - .end = U8500_SDI2_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = {IRQ_DB8500_SDMMC2, NO_IRQ}, -}; - -struct amba_device u8500_sdi3_device = { - .dev = { - .init_name = "sdi3", - }, - .res = { - .start = U8500_SDI3_BASE, - .end = U8500_SDI3_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = {IRQ_DB8500_SDMMC3, NO_IRQ}, -}; - -struct amba_device u8500_sdi4_device = { - .dev = { - .init_name = "sdi4", - }, - .res = { - .start = U8500_SDI4_BASE, - .end = U8500_SDI4_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = {IRQ_DB8500_SDMMC4, NO_IRQ}, -}; - -struct amba_device u8500_sdi5_device = { - .dev = { - .init_name = "sdi5", - }, - .res = { - .start = U8500_SDI5_BASE, - .end = U8500_SDI5_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = {IRQ_DB8500_SDMMC5, NO_IRQ}, -}; - static struct resource dma40_resources[] = { [0] = { .start = U8500_DMA_BASE, @@ -234,12 +68,72 @@ struct stedma40_chan_cfg dma40_memcpy_conf_log = { /* * Mapping between destination event lines and physical device address. - * The event line is tied to a device and therefor the address is constant. + * The event line is tied to a device and therefore the address is constant. + * When the address comes from a primecell it will be configured in runtime + * and we set the address to -1 as a placeholder. */ -static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV]; +static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV] = { + /* MUSB - these will be runtime-reconfigured */ + [DB8500_DMA_DEV39_USB_OTG_OEP_8] = -1, + [DB8500_DMA_DEV16_USB_OTG_OEP_7_15] = -1, + [DB8500_DMA_DEV17_USB_OTG_OEP_6_14] = -1, + [DB8500_DMA_DEV18_USB_OTG_OEP_5_13] = -1, + [DB8500_DMA_DEV19_USB_OTG_OEP_4_12] = -1, + [DB8500_DMA_DEV36_USB_OTG_OEP_3_11] = -1, + [DB8500_DMA_DEV37_USB_OTG_OEP_2_10] = -1, + [DB8500_DMA_DEV38_USB_OTG_OEP_1_9] = -1, + /* PrimeCells - run-time configured */ + [DB8500_DMA_DEV0_SPI0_TX] = -1, + [DB8500_DMA_DEV1_SD_MMC0_TX] = -1, + [DB8500_DMA_DEV2_SD_MMC1_TX] = -1, + [DB8500_DMA_DEV3_SD_MMC2_TX] = -1, + [DB8500_DMA_DEV8_SSP0_TX] = -1, + [DB8500_DMA_DEV9_SSP1_TX] = -1, + [DB8500_DMA_DEV11_UART2_TX] = -1, + [DB8500_DMA_DEV12_UART1_TX] = -1, + [DB8500_DMA_DEV13_UART0_TX] = -1, + [DB8500_DMA_DEV28_SD_MM2_TX] = -1, + [DB8500_DMA_DEV29_SD_MM0_TX] = -1, + [DB8500_DMA_DEV32_SD_MM1_TX] = -1, + [DB8500_DMA_DEV33_SPI2_TX] = -1, + [DB8500_DMA_DEV35_SPI1_TX] = -1, + [DB8500_DMA_DEV40_SPI3_TX] = -1, + [DB8500_DMA_DEV41_SD_MM3_TX] = -1, + [DB8500_DMA_DEV42_SD_MM4_TX] = -1, + [DB8500_DMA_DEV43_SD_MM5_TX] = -1, +}; /* Mapping between source event lines and physical device address */ -static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV]; +static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV] = { + /* MUSB - these will be runtime-reconfigured */ + [DB8500_DMA_DEV39_USB_OTG_IEP_8] = -1, + [DB8500_DMA_DEV16_USB_OTG_IEP_7_15] = -1, + [DB8500_DMA_DEV17_USB_OTG_IEP_6_14] = -1, + [DB8500_DMA_DEV18_USB_OTG_IEP_5_13] = -1, + [DB8500_DMA_DEV19_USB_OTG_IEP_4_12] = -1, + [DB8500_DMA_DEV36_USB_OTG_IEP_3_11] = -1, + [DB8500_DMA_DEV37_USB_OTG_IEP_2_10] = -1, + [DB8500_DMA_DEV38_USB_OTG_IEP_1_9] = -1, + /* PrimeCells */ + [DB8500_DMA_DEV0_SPI0_RX] = -1, + [DB8500_DMA_DEV1_SD_MMC0_RX] = -1, + [DB8500_DMA_DEV2_SD_MMC1_RX] = -1, + [DB8500_DMA_DEV3_SD_MMC2_RX] = -1, + [DB8500_DMA_DEV8_SSP0_RX] = -1, + [DB8500_DMA_DEV9_SSP1_RX] = -1, + [DB8500_DMA_DEV11_UART2_RX] = -1, + [DB8500_DMA_DEV12_UART1_RX] = -1, + [DB8500_DMA_DEV13_UART0_RX] = -1, + [DB8500_DMA_DEV28_SD_MM2_RX] = -1, + [DB8500_DMA_DEV29_SD_MM0_RX] = -1, + [DB8500_DMA_DEV32_SD_MM1_RX] = -1, + [DB8500_DMA_DEV33_SPI2_RX] = -1, + [DB8500_DMA_DEV35_SPI1_RX] = -1, + [DB8500_DMA_DEV40_SPI3_RX] = -1, + [DB8500_DMA_DEV41_SD_MM3_RX] = -1, + [DB8500_DMA_DEV42_SD_MM4_RX] = -1, + [DB8500_DMA_DEV43_SD_MM5_RX] = -1, +}; /* Reserved event lines for memcpy only */ static int dma40_memcpy_event[] = { @@ -295,7 +189,7 @@ struct resource keypad_resources[] = { }, }; -struct platform_device ux500_ske_keypad_device = { +struct platform_device u8500_ske_keypad_device = { .name = "nmk-ske-keypad", .id = -1, .num_resources = ARRAY_SIZE(keypad_resources), diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h new file mode 100644 index 000000000000..9cc6f8f5d3e6 --- /dev/null +++ b/arch/arm/mach-ux500/devices-db8500.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __DEVICES_DB8500_H +#define __DEVICES_DB8500_H + +#include "devices-common.h" + +struct ske_keypad_platform_data; +struct pl022_ssp_controller; + +static inline struct platform_device * +db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata) +{ + return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1, + U8500_SKE_BASE, + IRQ_DB8500_KB, pdata); +} + +static inline struct amba_device * +db8500_add_ssp(const char *name, resource_size_t base, int irq, + struct pl022_ssp_controller *pdata) +{ + return dbx500_add_amba_device(name, base, irq, pdata, SSP_PER_ID); +} + + +#define db8500_add_i2c0(pdata) \ + dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata) +#define db8500_add_i2c1(pdata) \ + dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata) +#define db8500_add_i2c2(pdata) \ + dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata) +#define db8500_add_i2c3(pdata) \ + dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata) +#define db8500_add_i2c4(pdata) \ + dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata) + +#define db8500_add_msp0_i2s(pdata) \ + dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) +#define db8500_add_msp1_i2s(pdata) \ + dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) +#define db8500_add_msp2_i2s(pdata) \ + dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) +#define db8500_add_msp3_i2s(pdata) \ + dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) + +#define db8500_add_msp0_spi(pdata) \ + dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) +#define db8500_add_msp1_spi(pdata) \ + dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) +#define db8500_add_msp2_spi(pdata) \ + dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) +#define db8500_add_msp3_spi(pdata) \ + dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) + +#define db8500_add_rtc() \ + dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC); + +#define db8500_add_usb(rx_cfg, tx_cfg) \ + ux500_add_usb(U8500_USBOTG_BASE, IRQ_DB8500_USBOTG, rx_cfg, tx_cfg) + +#define db8500_add_sdi0(pdata) \ + dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata) +#define db8500_add_sdi1(pdata) \ + dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata) +#define db8500_add_sdi2(pdata) \ + dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata) +#define db8500_add_sdi3(pdata) \ + dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata) +#define db8500_add_sdi4(pdata) \ + dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata) +#define db8500_add_sdi5(pdata) \ + dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata) + +#define db8500_add_ssp0(pdata) \ + db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata) +#define db8500_add_ssp1(pdata) \ + db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata) + +#define db8500_add_spi0(pdata) \ + dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata) +#define db8500_add_spi1(pdata) \ + dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata) +#define db8500_add_spi2(pdata) \ + dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata) +#define db8500_add_spi3(pdata) \ + dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata) + +#define db8500_add_uart0(pdata) \ + dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata) +#define db8500_add_uart1(pdata) \ + dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1, pdata) +#define db8500_add_uart2(pdata) \ + dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2, pdata) + +#endif diff --git a/arch/arm/mach-ux500/devices.c b/arch/arm/mach-ux500/devices.c index 8a268893cb7f..ea0a2f92ca70 100644 --- a/arch/arm/mach-ux500/devices.c +++ b/arch/arm/mach-ux500/devices.c @@ -14,69 +14,6 @@ #include <mach/hardware.h> #include <mach/setup.h> -#define __MEM_4K_RESOURCE(x) \ - .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} - -struct amba_device ux500_pl031_device = { - .dev = { - .init_name = "pl031", - }, - .res = { - .start = UX500_RTC_BASE, - .end = UX500_RTC_BASE + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - .irq = {IRQ_RTC_RTT, NO_IRQ}, -}; - -struct amba_device ux500_uart0_device = { - .dev = { .init_name = "uart0" }, - __MEM_4K_RESOURCE(UX500_UART0_BASE), - .irq = {IRQ_UART0, NO_IRQ}, -}; - -struct amba_device ux500_uart1_device = { - .dev = { .init_name = "uart1" }, - __MEM_4K_RESOURCE(UX500_UART1_BASE), - .irq = {IRQ_UART1, NO_IRQ}, -}; - -struct amba_device ux500_uart2_device = { - .dev = { .init_name = "uart2" }, - __MEM_4K_RESOURCE(UX500_UART2_BASE), - .irq = {IRQ_UART2, NO_IRQ}, -}; - -#define UX500_I2C_RESOURCES(id, size) \ -static struct resource ux500_i2c##id##_resources[] = { \ - [0] = { \ - .start = UX500_I2C##id##_BASE, \ - .end = UX500_I2C##id##_BASE + size - 1, \ - .flags = IORESOURCE_MEM, \ - }, \ - [1] = { \ - .start = IRQ_I2C##id, \ - .end = IRQ_I2C##id, \ - .flags = IORESOURCE_IRQ \ - } \ -} - -UX500_I2C_RESOURCES(1, SZ_4K); -UX500_I2C_RESOURCES(2, SZ_4K); -UX500_I2C_RESOURCES(3, SZ_4K); - -#define UX500_I2C_PDEVICE(cid) \ -struct platform_device ux500_i2c##cid##_device = { \ - .name = "nmk-i2c", \ - .id = cid, \ - .num_resources = 2, \ - .resource = ux500_i2c##cid##_resources, \ -} - -UX500_I2C_PDEVICE(1); -UX500_I2C_PDEVICE(2); -UX500_I2C_PDEVICE(3); - void __init amba_add_devices(struct amba_device *devs[], int num) { int i; diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c new file mode 100644 index 000000000000..1cfab68ae417 --- /dev/null +++ b/arch/arm/mach-ux500/dma-db5500.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * Author: Rabin Vincent <rabinv.vincent@stericsson.com> for ST-Ericsson + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <plat/ste_dma40.h> +#include <mach/setup.h> +#include <mach/hardware.h> + +#include "ste-dma40-db5500.h" + +static struct resource dma40_resources[] = { + [0] = { + .start = U5500_DMA_BASE, + .end = U5500_DMA_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + .name = "base", + }, + [1] = { + .start = U5500_DMA_LCPA_BASE, + .end = U5500_DMA_LCPA_BASE + 2 * SZ_1K - 1, + .flags = IORESOURCE_MEM, + .name = "lcpa", + }, + [2] = { + .start = IRQ_DB5500_DMA, + .end = IRQ_DB5500_DMA, + .flags = IORESOURCE_IRQ + } +}; + +/* Default configuration for physical memcpy */ +static struct stedma40_chan_cfg dma40_memcpy_conf_phy = { + .mode = STEDMA40_MODE_PHYSICAL, + .dir = STEDMA40_MEM_TO_MEM, + + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .src_info.psize = STEDMA40_PSIZE_PHY_1, + .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, + + .dst_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.psize = STEDMA40_PSIZE_PHY_1, + .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, +}; + +/* Default configuration for logical memcpy */ +static struct stedma40_chan_cfg dma40_memcpy_conf_log = { + .dir = STEDMA40_MEM_TO_MEM, + + .src_info.data_width = STEDMA40_BYTE_WIDTH, + .src_info.psize = STEDMA40_PSIZE_LOG_1, + .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, + + .dst_info.data_width = STEDMA40_BYTE_WIDTH, + .dst_info.psize = STEDMA40_PSIZE_LOG_1, + .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, +}; + +/* + * Mapping between soruce event lines and physical device address This was + * created assuming that the event line is tied to a device and therefore the + * address is constant, however this is not true for at least USB, and the + * values are just placeholders for USB. This table is preserved and used for + * now. + */ +static const dma_addr_t dma40_rx_map[DB5500_DMA_NR_DEV] = { + [DB5500_DMA_DEV24_SDMMC0_RX] = -1, + [DB5500_DMA_DEV38_USB_OTG_IEP_8] = -1, + [DB5500_DMA_DEV23_USB_OTG_IEP_7_15] = -1, + [DB5500_DMA_DEV22_USB_OTG_IEP_6_14] = -1, + [DB5500_DMA_DEV21_USB_OTG_IEP_5_13] = -1, + [DB5500_DMA_DEV20_USB_OTG_IEP_4_12] = -1, + [DB5500_DMA_DEV6_USB_OTG_IEP_3_11] = -1, + [DB5500_DMA_DEV5_USB_OTG_IEP_2_10] = -1, + [DB5500_DMA_DEV4_USB_OTG_IEP_1_9] = -1, +}; + +/* Mapping between destination event lines and physical device address */ +static const dma_addr_t dma40_tx_map[DB5500_DMA_NR_DEV] = { + [DB5500_DMA_DEV24_SDMMC0_TX] = -1, + [DB5500_DMA_DEV38_USB_OTG_OEP_8] = -1, + [DB5500_DMA_DEV23_USB_OTG_OEP_7_15] = -1, + [DB5500_DMA_DEV22_USB_OTG_OEP_6_14] = -1, + [DB5500_DMA_DEV21_USB_OTG_OEP_5_13] = -1, + [DB5500_DMA_DEV20_USB_OTG_OEP_4_12] = -1, + [DB5500_DMA_DEV6_USB_OTG_OEP_3_11] = -1, + [DB5500_DMA_DEV5_USB_OTG_OEP_2_10] = -1, + [DB5500_DMA_DEV4_USB_OTG_OEP_1_9] = -1, +}; + +static int dma40_memcpy_event[] = { + DB5500_DMA_MEMCPY_TX_1, + DB5500_DMA_MEMCPY_TX_2, + DB5500_DMA_MEMCPY_TX_3, + DB5500_DMA_MEMCPY_TX_4, + DB5500_DMA_MEMCPY_TX_5, +}; + +static struct stedma40_platform_data dma40_plat_data = { + .dev_len = ARRAY_SIZE(dma40_rx_map), + .dev_rx = dma40_rx_map, + .dev_tx = dma40_tx_map, + .memcpy = dma40_memcpy_event, + .memcpy_len = ARRAY_SIZE(dma40_memcpy_event), + .memcpy_conf_phy = &dma40_memcpy_conf_phy, + .memcpy_conf_log = &dma40_memcpy_conf_log, + .disabled_channels = {-1}, +}; + +static struct platform_device dma40_device = { + .dev = { + .platform_data = &dma40_plat_data, + }, + .name = "dma40", + .id = 0, + .num_resources = ARRAY_SIZE(dma40_resources), + .resource = dma40_resources +}; + +void __init db5500_dma_init(void) +{ + int ret; + + ret = platform_device_register(&dma40_device); + if (ret) + dev_err(&dma40_device.dev, "unable to register device: %d\n", ret); + +} diff --git a/arch/arm/mach-ux500/headsmp.S b/arch/arm/mach-ux500/headsmp.S index a6be2cdf2b2f..64fa451edcfd 100644 --- a/arch/arm/mach-ux500/headsmp.S +++ b/arch/arm/mach-ux500/headsmp.S @@ -23,7 +23,6 @@ ENTRY(u8500_secondary_startup) ldmia r4, {r5, r6} sub r4, r4, r5 add r6, r6, r4 - dsb pen: ldr r7, [r6] cmp r7, r0 bne pen diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c index b782a03024be..dd8037ebccf8 100644 --- a/arch/arm/mach-ux500/hotplug.c +++ b/arch/arm/mach-ux500/hotplug.c @@ -11,14 +11,11 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/smp.h> -#include <linux/completion.h> #include <asm/cacheflush.h> extern volatile int pen_release; -static DECLARE_COMPLETION(cpu_killed); - static inline void platform_do_lowpower(unsigned int cpu) { flush_cache_all(); @@ -38,7 +35,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -48,19 +45,6 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { -#ifdef DEBUG - unsigned int this_cpu = hard_smp_processor_id(); - - if (cpu != this_cpu) { - printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", - this_cpu, cpu); - BUG(); - } -#endif - - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* directly enter low power state, skipping secure registers */ platform_do_lowpower(cpu); } diff --git a/arch/arm/mach-ux500/id.c b/arch/arm/mach-ux500/id.c new file mode 100644 index 000000000000..d35122ebc67b --- /dev/null +++ b/arch/arm/mach-ux500/id.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> + +#include <asm/cputype.h> +#include <asm/tlbflush.h> +#include <asm/cacheflush.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/setup.h> + +struct dbx500_asic_id dbx500_id; + +static unsigned int ux500_read_asicid(phys_addr_t addr) +{ + phys_addr_t base = addr & ~0xfff; + struct map_desc desc = { + .virtual = IO_ADDRESS(base), + .pfn = __phys_to_pfn(base), + .length = SZ_16K, + .type = MT_DEVICE, + }; + + iotable_init(&desc, 1); + + /* As in devicemaps_init() */ + local_flush_tlb_all(); + flush_cache_all(); + + return readl(__io_address(addr)); +} + +static void ux500_print_soc_info(unsigned int asicid) +{ + unsigned int rev = dbx500_revision(); + + pr_info("DB%4x ", dbx500_partnumber()); + + if (rev == 0x01) + pr_cont("Early Drop"); + else if (rev >= 0xA0) + pr_cont("v%d.%d" , (rev >> 4) - 0xA + 1, rev & 0xf); + else + pr_cont("Unknown"); + + pr_cont(" [%#010x]\n", asicid); +} + +static unsigned int partnumber(unsigned int asicid) +{ + return (asicid >> 8) & 0xffff; +} + +/* + * SOC MIDR ASICID ADDRESS ASICID VALUE + * DB8500ed 0x410fc090 0x9001FFF4 0x00850001 + * DB8500v1 0x411fc091 0x9001FFF4 0x008500A0 + * DB8500v1.1 0x411fc091 0x9001FFF4 0x008500A1 + * DB8500v2 0x412fc091 0x9001DBF4 0x008500B0 + * DB5500v1 0x412fc091 0x9001FFF4 0x005500A0 + */ + +void __init ux500_map_io(void) +{ + unsigned int cpuid = read_cpuid_id(); + unsigned int asicid = 0; + phys_addr_t addr = 0; + + switch (cpuid) { + case 0x410fc090: /* DB8500ed */ + case 0x411fc091: /* DB8500v1 */ + addr = 0x9001FFF4; + break; + + case 0x412fc091: /* DB8500v2 / DB5500v1 */ + asicid = ux500_read_asicid(0x9001DBF4); + if (partnumber(asicid) == 0x8500) + /* DB8500v2 */ + break; + + /* DB5500v1 */ + addr = 0x9001FFF4; + break; + } + + if (addr) + asicid = ux500_read_asicid(addr); + + if (!asicid) { + pr_err("Unable to identify SoC\n"); + ux500_unknown_soc(); + } + + dbx500_id.process = asicid >> 24; + dbx500_id.partnumber = partnumber(asicid); + dbx500_id.revision = asicid & 0xff; + + ux500_print_soc_info(asicid); +} diff --git a/arch/arm/mach-ux500/include/mach/db5500-regs.h b/arch/arm/mach-ux500/include/mach/db5500-regs.h index 3eafc0e24ba5..bd88c1e74060 100644 --- a/arch/arm/mach-ux500/include/mach/db5500-regs.h +++ b/arch/arm/mach-ux500/include/mach/db5500-regs.h @@ -114,4 +114,8 @@ #define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20) #define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F) +#define U5500_ESRAM_BASE 0x40000000 +#define U5500_ESRAM_DMA_LCPA_OFFSET 0x10000 +#define U5500_DMA_LCPA_BASE (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET) + #endif diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h index f07d0986409d..0fefb34c11e4 100644 --- a/arch/arm/mach-ux500/include/mach/db8500-regs.h +++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h @@ -92,7 +92,8 @@ #define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000) #define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000) #define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000) -#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x0f000) +#define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000) +#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000) /* per3 base addresses */ #define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000) diff --git a/arch/arm/mach-ux500/include/mach/debug-macro.S b/arch/arm/mach-ux500/include/mach/debug-macro.S index be7c0f14e310..700fb05ee815 100644 --- a/arch/arm/mach-ux500/include/mach/debug-macro.S +++ b/arch/arm/mach-ux500/include/mach/debug-macro.S @@ -14,7 +14,24 @@ #error Invalid Ux500 debug UART #endif -#define __UX500_UART(n) UX500_UART##n##_BASE +/* + * DEBUG_LL only works if only one SOC is built in. We don't use #else below + * in order to get "__UX500_UART redefined" warnings if more than one SOC is + * built, so that there's some hint during the build that something is wrong. + */ + +#ifdef CONFIG_UX500_SOC_DB5500 +#define __UX500_UART(n) U5500_UART##n##_BASE +#endif + +#ifdef CONFIG_UX500_SOC_DB8500 +#define __UX500_UART(n) U8500_UART##n##_BASE +#endif + +#ifndef __UX500_UART +#error Unknown SOC +#endif + #define UX500_UART(n) __UX500_UART(n) #define UART_BASE UX500_UART(CONFIG_UX500_DEBUG_UART) diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h index b91a4d1211a2..020b6369a30a 100644 --- a/arch/arm/mach-ux500/include/mach/devices.h +++ b/arch/arm/mach-ux500/include/mach/devices.h @@ -14,27 +14,10 @@ extern struct platform_device u5500_gpio_devs[]; extern struct platform_device u8500_gpio_devs[]; extern struct amba_device ux500_pl031_device; -extern struct amba_device u8500_ssp0_device; -extern struct amba_device ux500_uart0_device; -extern struct amba_device ux500_uart1_device; -extern struct amba_device ux500_uart2_device; -extern struct platform_device ux500_i2c1_device; -extern struct platform_device ux500_i2c2_device; -extern struct platform_device ux500_i2c3_device; - -extern struct platform_device u8500_i2c0_device; -extern struct platform_device u8500_i2c4_device; extern struct platform_device u8500_dma40_device; extern struct platform_device ux500_ske_keypad_device; -extern struct amba_device u8500_sdi0_device; -extern struct amba_device u8500_sdi1_device; -extern struct amba_device u8500_sdi2_device; -extern struct amba_device u8500_sdi3_device; -extern struct amba_device u8500_sdi4_device; -extern struct amba_device u8500_sdi5_device; - void dma40_u8500ed_fixup(void); #endif diff --git a/arch/arm/mach-ux500/include/mach/entry-macro.S b/arch/arm/mach-ux500/include/mach/entry-macro.S index 60ea88db8283..071bba94f727 100644 --- a/arch/arm/mach-ux500/include/mach/entry-macro.S +++ b/arch/arm/mach-ux500/include/mach/entry-macro.S @@ -11,79 +11,10 @@ * warranty of any kind, whether express or implied. */ #include <mach/hardware.h> -#include <asm/hardware/gic.h> +#include <asm/hardware/entry-macro-gic.S> .macro disable_fiq .endm - .macro get_irqnr_preamble, base, tmp - ldr \base, =IO_ADDRESS(UX500_GIC_CPU_BASE) - .endm - .macro arch_ret_to_user, tmp1, tmp2 .endm - - /* - * The interrupt numbering scheme is defined in the - * interrupt controller spec. To wit: - * - * Interrupts 0-15 are IPI - * 16-28 are reserved - * 29-31 are local. We allow 30 to be used for the watchdog. - * 32-1020 are global - * 1021-1022 are reserved - * 1023 is "spurious" (no interrupt) - * - * For now, we ignore all local interrupts so only return an - * interrupt if it's between 30 and 1020. The test_for_ipi - * routine below will pick up on IPIs. - * - * A simple read from the controller will tell us the number - * of the highest priority enabled interrupt. We then just - * need to check whether it is in the valid range for an - * IRQ (30-1020 inclusive). - */ - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - - /* bits 12-10 = src CPU, 9-0 = int # */ - ldr \irqstat, [\base, #GIC_CPU_INTACK] - - ldr \tmp, =1021 - - bic \irqnr, \irqstat, #0x1c00 - - cmp \irqnr, #29 - cmpcc \irqnr, \irqnr - cmpne \irqnr, \tmp - cmpcs \irqnr, \irqnr - - .endm - - /* We assume that irqstat (the raw value of the IRQ - * acknowledge register) is preserved from the macro above. - * If there is an IPI, we immediately signal end of - * interrupt on the controller, since this requires the - * original irqstat value which we won't easily be able - * to recreate later. - */ - - .macro test_for_ipi, irqnr, irqstat, base, tmp - bic \irqnr, \irqstat, #0x1c00 - cmp \irqnr, #16 - strcc \irqstat, [\base, #GIC_CPU_EOI] - cmpcs \irqnr, \irqnr - .endm - - /* As above, this assumes that irqstat and base - * are preserved.. - */ - - .macro test_for_ltirq, irqnr, irqstat, base, tmp - bic \irqnr, \irqstat, #0x1c00 - mov \tmp, #0 - cmp \irqnr, #29 - moveq \tmp, #1 - streq \irqstat, [\base, #GIC_CPU_EOI] - cmp \tmp, #0 - .endm diff --git a/arch/arm/mach-ux500/include/mach/gpio.h b/arch/arm/mach-ux500/include/mach/gpio.h index d548a622e7d2..3c4cd31ad9f7 100644 --- a/arch/arm/mach-ux500/include/mach/gpio.h +++ b/arch/arm/mach-ux500/include/mach/gpio.h @@ -9,42 +9,4 @@ #include <plat/gpio.h> -#define __GPIO_RESOURCE(soc, block) \ - { \ - .start = soc##_GPIOBANK##block##_BASE, \ - .end = soc##_GPIOBANK##block##_BASE + 127, \ - .flags = IORESOURCE_MEM, \ - }, \ - { \ - .start = IRQ_GPIO##block, \ - .end = IRQ_GPIO##block, \ - .flags = IORESOURCE_IRQ, \ - } - -#define __GPIO_DEVICE(soc, block) \ - { \ - .name = "gpio", \ - .id = block, \ - .num_resources = 2, \ - .resource = &soc##_gpio_resources[block * 2], \ - .dev = { \ - .platform_data = &soc##_gpio_data[block], \ - }, \ - } - -#define GPIO_DATA(_name, first) \ - { \ - .name = _name, \ - .first_gpio = first, \ - .first_irq = NOMADIK_GPIO_TO_IRQ(first), \ - } - -#ifdef CONFIG_UX500_SOC_DB8500 -#define GPIO_RESOURCE(block) __GPIO_RESOURCE(U8500, block) -#define GPIO_DEVICE(block) __GPIO_DEVICE(u8500, block) -#elif defined(CONFIG_UX500_SOC_DB5500) -#define GPIO_RESOURCE(block) __GPIO_RESOURCE(U5500, block) -#define GPIO_DEVICE(block) __GPIO_DEVICE(u5500, block) -#endif - #endif /* __ASM_ARCH_GPIO_H */ diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h index 32e883a8f2a2..bf63f2631ba0 100644 --- a/arch/arm/mach-ux500/include/mach/hardware.h +++ b/arch/arm/mach-ux500/include/mach/hardware.h @@ -29,118 +29,14 @@ #include <mach/db8500-regs.h> #include <mach/db5500-regs.h> -#ifdef CONFIG_UX500_SOC_DB8500 -#define UX500(periph) U8500_##periph##_BASE -#elif defined(CONFIG_UX500_SOC_DB5500) -#define UX500(periph) U5500_##periph##_BASE -#endif - -#define UX500_BACKUPRAM0_BASE UX500(BACKUPRAM0) -#define UX500_BACKUPRAM1_BASE UX500(BACKUPRAM1) -#define UX500_B2R2_BASE UX500(B2R2) - -#define UX500_CLKRST1_BASE UX500(CLKRST1) -#define UX500_CLKRST2_BASE UX500(CLKRST2) -#define UX500_CLKRST3_BASE UX500(CLKRST3) -#define UX500_CLKRST5_BASE UX500(CLKRST5) -#define UX500_CLKRST6_BASE UX500(CLKRST6) - -#define UX500_DMA_BASE UX500(DMA) -#define UX500_FSMC_BASE UX500(FSMC) - -#define UX500_GIC_CPU_BASE UX500(GIC_CPU) -#define UX500_GIC_DIST_BASE UX500(GIC_DIST) - -#define UX500_I2C1_BASE UX500(I2C1) -#define UX500_I2C2_BASE UX500(I2C2) -#define UX500_I2C3_BASE UX500(I2C3) - -#define UX500_L2CC_BASE UX500(L2CC) -#define UX500_MCDE_BASE UX500(MCDE) -#define UX500_MTU0_BASE UX500(MTU0) -#define UX500_MTU1_BASE UX500(MTU1) -#define UX500_PRCMU_BASE UX500(PRCMU) - -#define UX500_RNG_BASE UX500(RNG) -#define UX500_RTC_BASE UX500(RTC) - -#define UX500_SCU_BASE UX500(SCU) - -#define UX500_SDI0_BASE UX500(SDI0) -#define UX500_SDI1_BASE UX500(SDI1) -#define UX500_SDI2_BASE UX500(SDI2) -#define UX500_SDI3_BASE UX500(SDI3) -#define UX500_SDI4_BASE UX500(SDI4) - -#define UX500_SPI0_BASE UX500(SPI0) -#define UX500_SPI1_BASE UX500(SPI1) -#define UX500_SPI2_BASE UX500(SPI2) -#define UX500_SPI3_BASE UX500(SPI3) - -#define UX500_SIA_BASE UX500(SIA) -#define UX500_SVA_BASE UX500(SVA) - -#define UX500_TWD_BASE UX500(TWD) - -#define UX500_UART0_BASE UX500(UART0) -#define UX500_UART1_BASE UX500(UART1) -#define UX500_UART2_BASE UX500(UART2) - -#define UX500_USBOTG_BASE UX500(USBOTG) - /* ST-Ericsson modified pl022 id */ #define SSP_PER_ID 0x01080022 #ifndef __ASSEMBLY__ -#include <asm/cputype.h> - -static inline bool cpu_is_u8500(void) -{ -#ifdef CONFIG_UX500_SOC_DB8500 - return 1; -#else - return 0; -#endif -} - -#define CPUID_DB8500ED 0x410fc090 -#define CPUID_DB8500V1 0x411fc091 -#define CPUID_DB8500V2 0x412fc091 +#include <mach/id.h> -static inline bool cpu_is_u8500ed(void) -{ - return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500ED); -} - -static inline bool cpu_is_u8500v1(void) -{ - return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V1); -} - -static inline bool cpu_is_u8500v2(void) -{ - return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V2); -} - -#ifdef CONFIG_UX500_SOC_DB8500 -bool cpu_is_u8500v10(void); -bool cpu_is_u8500v11(void); -bool cpu_is_u8500v20(void); -#else -static inline bool cpu_is_u8500v10(void) { return false; } -static inline bool cpu_is_u8500v11(void) { return false; } -static inline bool cpu_is_u8500v20(void) { return false; } -#endif - -static inline bool cpu_is_u5500(void) -{ -#ifdef CONFIG_UX500_SOC_DB5500 - return 1; -#else - return 0; -#endif -} +#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) #endif diff --git a/arch/arm/mach-ux500/include/mach/id.h b/arch/arm/mach-ux500/include/mach/id.h new file mode 100644 index 000000000000..f1288d10b6ab --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/id.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __MACH_UX500_ID +#define __MACH_UX500_ID + +/** + * struct dbx500_asic_id - fields of the ASIC ID + * @process: the manufacturing process, 0x40 is 40 nm 0x00 is "standard" + * @partnumber: hithereto 0x8500 for DB8500 + * @revision: version code in the series + */ +struct dbx500_asic_id { + u16 partnumber; + u8 revision; + u8 process; +}; + +extern struct dbx500_asic_id dbx500_id; + +static inline unsigned int __attribute_const__ dbx500_partnumber(void) +{ + return dbx500_id.partnumber; +} + +static inline unsigned int __attribute_const__ dbx500_revision(void) +{ + return dbx500_id.revision; +} + +/* + * SOCs + */ + +static inline bool __attribute_const__ cpu_is_u8500(void) +{ + return dbx500_partnumber() == 0x8500; +} + +static inline bool __attribute_const__ cpu_is_u5500(void) +{ + return dbx500_partnumber() == 0x5500; +} + +/* + * 8500 revisions + */ + +static inline bool __attribute_const__ cpu_is_u8500ed(void) +{ + return cpu_is_u8500() && dbx500_revision() == 0x00; +} + +static inline bool __attribute_const__ cpu_is_u8500v1(void) +{ + return cpu_is_u8500() && (dbx500_revision() & 0xf0) == 0xA0; +} + +static inline bool __attribute_const__ cpu_is_u8500v10(void) +{ + return cpu_is_u8500() && dbx500_revision() == 0xA0; +} + +static inline bool __attribute_const__ cpu_is_u8500v11(void) +{ + return cpu_is_u8500() && dbx500_revision() == 0xA1; +} + +static inline bool __attribute_const__ cpu_is_u8500v2(void) +{ + return cpu_is_u8500() && ((dbx500_revision() & 0xf0) == 0xB0); +} + +#define ux500_unknown_soc() BUG() + +#endif diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h index cca4f705601e..7cdeb2af0ebb 100644 --- a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h +++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h @@ -8,12 +8,36 @@ #ifndef __MACH_IRQS_BOARD_MOP500_H #define __MACH_IRQS_BOARD_MOP500_H -#define AB8500_NR_IRQS 104 +/* Number of AB8500 irqs is taken from header file */ +#include <linux/mfd/ab8500.h> #define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START #define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \ + AB8500_NR_IRQS) -#define MOP500_IRQ_END MOP500_AB8500_IRQ_END + +/* TC35892 */ +#define TC35892_NR_INTERNAL_IRQS 8 +#define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x)) +#define TC35892_NR_GPIOS 24 +#define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS) + +#define MOP500_EGPIO_NR_IRQS TC35892_NR_IRQS + +#define MOP500_EGPIO_IRQ_BASE MOP500_AB8500_IRQ_END +#define MOP500_EGPIO_IRQ_END (MOP500_EGPIO_IRQ_BASE \ + + MOP500_EGPIO_NR_IRQS) +/* STMPE1601 irqs */ +#define STMPE_NR_INTERNAL_IRQS 9 +#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x)) +#define STMPE_NR_GPIOS 24 +#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS) + +#define MOP500_STMPE1601_IRQBASE MOP500_EGPIO_IRQ_END +#define MOP500_STMPE1601_IRQ(x) (MOP500_STMPE1601_IRQBASE + (x)) + +#define MOP500_NR_IRQS MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS) + +#define MOP500_IRQ_END MOP500_NR_IRQS #if MOP500_IRQ_END > IRQ_BOARD_END #undef IRQ_BOARD_END diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h index 693aa57de88d..ba1294c13c4d 100644 --- a/arch/arm/mach-ux500/include/mach/irqs.h +++ b/arch/arm/mach-ux500/include/mach/irqs.h @@ -21,50 +21,6 @@ /* Interrupt numbers generic for shared peripheral */ #define IRQ_MTU0 (IRQ_SHPI_START + 4) -#define IRQ_SPI2 (IRQ_SHPI_START + 6) -#define IRQ_SPI0 (IRQ_SHPI_START + 8) -#define IRQ_UART0 (IRQ_SHPI_START + 11) -#define IRQ_I2C3 (IRQ_SHPI_START + 12) -#define IRQ_SSP0 (IRQ_SHPI_START + 14) -#define IRQ_MTU1 (IRQ_SHPI_START + 17) -#define IRQ_RTC_RTT (IRQ_SHPI_START + 18) -#define IRQ_UART1 (IRQ_SHPI_START + 19) -#define IRQ_I2C0 (IRQ_SHPI_START + 21) -#define IRQ_I2C1 (IRQ_SHPI_START + 22) -#define IRQ_USBOTG (IRQ_SHPI_START + 23) -#define IRQ_DMA (IRQ_SHPI_START + 25) -#define IRQ_UART2 (IRQ_SHPI_START + 26) -#define IRQ_HSIR_EXCEP (IRQ_SHPI_START + 29) -#define IRQ_MSP0 (IRQ_SHPI_START + 31) -#define IRQ_HSIR_CH0_OVRRUN (IRQ_SHPI_START + 32) -#define IRQ_HSIR_CH1_OVRRUN (IRQ_SHPI_START + 33) -#define IRQ_HSIR_CH2_OVRRUN (IRQ_SHPI_START + 34) -#define IRQ_HSIR_CH3_OVRRUN (IRQ_SHPI_START + 35) -#define IRQ_AB8500 (IRQ_SHPI_START + 40) -#define IRQ_PRCMU (IRQ_SHPI_START + 47) -#define IRQ_DISP (IRQ_SHPI_START + 48) -#define IRQ_SiPI3 (IRQ_SHPI_START + 49) -#define IRQ_I2C4 (IRQ_SHPI_START + 51) -#define IRQ_SSP1 (IRQ_SHPI_START + 52) -#define IRQ_I2C2 (IRQ_SHPI_START + 55) -#define IRQ_SDMMC0 (IRQ_SHPI_START + 60) -#define IRQ_MSP1 (IRQ_SHPI_START + 62) -#define IRQ_SPI1 (IRQ_SHPI_START + 96) -#define IRQ_MSP2 (IRQ_SHPI_START + 98) -#define IRQ_SDMMC4 (IRQ_SHPI_START + 99) -#define IRQ_HSIRD0 (IRQ_SHPI_START + 104) -#define IRQ_HSIRD1 (IRQ_SHPI_START + 105) -#define IRQ_HSITD0 (IRQ_SHPI_START + 106) -#define IRQ_HSITD1 (IRQ_SHPI_START + 107) -#define IRQ_GPIO0 (IRQ_SHPI_START + 119) -#define IRQ_GPIO1 (IRQ_SHPI_START + 120) -#define IRQ_GPIO2 (IRQ_SHPI_START + 121) -#define IRQ_GPIO3 (IRQ_SHPI_START + 122) -#define IRQ_GPIO4 (IRQ_SHPI_START + 123) -#define IRQ_GPIO5 (IRQ_SHPI_START + 124) -#define IRQ_GPIO6 (IRQ_SHPI_START + 125) -#define IRQ_GPIO7 (IRQ_SHPI_START + 126) -#define IRQ_GPIO8 (IRQ_SHPI_START + 127) /* There are 128 shared peripheral interrupts assigned to * INTID[160:32]. The first 32 interrupts are reserved. @@ -80,7 +36,7 @@ /* This will be overridden by board-specific irq headers */ #define IRQ_BOARD_END IRQ_BOARD_START -#ifdef CONFIG_MACH_U8500_MOP +#ifdef CONFIG_MACH_U8500 #include <mach/irqs-board-mop500.h> #endif diff --git a/arch/arm/mach-ux500/include/mach/mbox.h b/arch/arm/mach-ux500/include/mach/mbox-db5500.h index 7f9da4d2fbda..7f9da4d2fbda 100644 --- a/arch/arm/mach-ux500/include/mach/mbox.h +++ b/arch/arm/mach-ux500/include/mach/mbox-db5500.h diff --git a/arch/arm/mach-ux500/include/mach/memory.h b/arch/arm/mach-ux500/include/mach/memory.h index 510571a59e25..2ef697a67006 100644 --- a/arch/arm/mach-ux500/include/mach/memory.h +++ b/arch/arm/mach-ux500/include/mach/memory.h @@ -12,7 +12,7 @@ /* * Physical DRAM offset. */ -#define PHYS_OFFSET UL(0x00000000) +#define PLAT_PHYS_OFFSET UL(0x00000000) #define BUS_OFFSET UL(0x00000000) #endif diff --git a/arch/arm/mach-ux500/include/mach/prcmu-defs.h b/arch/arm/mach-ux500/include/mach/prcmu-defs.h new file mode 100644 index 000000000000..848ba64b561f --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/prcmu-defs.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * Author: Martin Persson <martin.persson@stericsson.com> + * + * License Terms: GNU General Public License v2 + * + * PRCM Unit definitions + */ + +#ifndef __MACH_PRCMU_DEFS_H +#define __MACH_PRCMU_DEFS_H + +enum prcmu_cpu_opp { + CPU_OPP_INIT = 0x00, + CPU_OPP_NO_CHANGE = 0x01, + CPU_OPP_100 = 0x02, + CPU_OPP_50 = 0x03, + CPU_OPP_MAX = 0x04, + CPU_OPP_EXT_CLK = 0x07 +}; +enum prcmu_ape_opp { + APE_OPP_NO_CHANGE = 0x00, + APE_OPP_100 = 0x02, + APE_OPP_50 = 0x03, +}; + +#endif /* __MACH_PRCMU_DEFS_H */ diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/arch/arm/mach-ux500/include/mach/prcmu-regs.h index 8885f39a6421..455467e88791 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu-regs.h +++ b/arch/arm/mach-ux500/include/mach/prcmu-regs.h @@ -1,10 +1,15 @@ /* - * Copyright (c) 2009 ST-Ericsson SA + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 * - * 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. + * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * + * License Terms: GNU General Public License v2 + * + * PRCM Unit registers */ + #ifndef __MACH_PRCMU_REGS_H #define __MACH_PRCMU_REGS_H @@ -88,4 +93,4 @@ /* Miscellaneous unit registers */ #define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324) -#endif /* __MACH_PRCMU__REGS_H */ +#endif /* __MACH_PRCMU_REGS_H */ diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h index 549843ff6dbe..c49e456162ef 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu.h +++ b/arch/arm/mach-ux500/include/mach/prcmu.h @@ -2,14 +2,27 @@ * Copyright (C) STMicroelectronics 2009 * Copyright (C) ST-Ericsson SA 2010 * + * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> + * * License Terms: GNU General Public License v2 * - * PRCMU f/w APIs + * PRCM Unit f/w API */ #ifndef __MACH_PRCMU_H #define __MACH_PRCMU_H +#include <mach/prcmu-defs.h> +void __init prcmu_early_init(void); int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size); int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); +int prcmu_set_ape_opp(enum prcmu_ape_opp opp); +int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp); +int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp, + enum prcmu_cpu_opp cpu_opp); +int prcmu_get_ape_opp(void); +int prcmu_get_cpu_opp(void); +bool prcmu_has_arm_maxopp(void); #endif /* __MACH_PRCMU_H */ diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h index 54bbe648bf58..a7d363fdb4cd 100644 --- a/arch/arm/mach-ux500/include/mach/setup.h +++ b/arch/arm/mach-ux500/include/mach/setup.h @@ -14,18 +14,23 @@ #include <asm/mach/time.h> #include <linux/init.h> -extern void __init ux500_map_io(void); +void __init ux500_map_io(void); extern void __init u5500_map_io(void); extern void __init u8500_map_io(void); -extern void __init ux500_init_devices(void); extern void __init u5500_init_devices(void); extern void __init u8500_init_devices(void); extern void __init ux500_init_irq(void); + +extern void __init u5500_sdi_init(void); + +extern void __init db5500_dma_init(void); + /* We re-use nomadik_timer for this platform */ extern void nmdk_timer_init(void); +struct amba_device; extern void __init amba_add_devices(struct amba_device *devs[], int num); struct sys_timer; diff --git a/arch/arm/mach-ux500/include/mach/smp.h b/arch/arm/mach-ux500/include/mach/smp.h index 197e8417375e..ca2b15b1b3b1 100644 --- a/arch/arm/mach-ux500/include/mach/smp.h +++ b/arch/arm/mach-ux500/include/mach/smp.h @@ -10,7 +10,6 @@ #define ASMARM_ARCH_SMP_H #include <asm/hardware/gic.h> -#include <asm/smp_mpidr.h> /* This is required to wakeup the secondary core */ extern void u8500_secondary_startup(void); @@ -18,8 +17,8 @@ extern void u8500_secondary_startup(void); /* * We use IRQ1 as the IPI */ -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h index 0271ca0a83df..ab0fe1432fae 100644 --- a/arch/arm/mach-ux500/include/mach/uncompress.h +++ b/arch/arm/mach-ux500/include/mach/uncompress.h @@ -19,38 +19,47 @@ #define __ASM_ARCH_UNCOMPRESS_H #include <asm/setup.h> +#include <asm/mach-types.h> #include <linux/io.h> +#include <linux/amba/serial.h> #include <mach/hardware.h> -#define U8500_UART_DR 0x80007000 -#define U8500_UART_LCRH 0x8000702c -#define U8500_UART_CR 0x80007030 -#define U8500_UART_FR 0x80007018 +static u32 ux500_uart_base; static void putc(const char c) { /* Do nothing if the UART is not enabled. */ - if (!(__raw_readb(U8500_UART_CR) & 0x1)) + if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1)) return; if (c == '\n') putc('\r'); - while (__raw_readb(U8500_UART_FR) & (1 << 5)) + while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 5)) barrier(); - __raw_writeb(c, U8500_UART_DR); + __raw_writeb(c, ux500_uart_base + UART01x_DR); } static void flush(void) { - if (!(__raw_readb(U8500_UART_CR) & 0x1)) + if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1)) return; - while (__raw_readb(U8500_UART_FR) & (1 << 3)) + while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 3)) barrier(); } static inline void arch_decomp_setup(void) { + /* Check in run time if we run on an U8500 or U5500 */ + if (machine_is_u8500() || + machine_is_svp8500v1() || + machine_is_svp8500v2() || + machine_is_hrefv60()) + ux500_uart_base = U8500_UART2_BASE; + else if (machine_is_u5500()) + ux500_uart_base = U5500_UART0_BASE; + else /* not much can be done to help here */ + ux500_uart_base = U8500_UART2_BASE; } #define arch_decomp_wdog() /* nothing to do here */ diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h new file mode 100644 index 000000000000..d3739d418813 --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/usb.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef __ASM_ARCH_USB_H +#define __ASM_ARCH_USB_H + +#include <linux/dmaengine.h> + +#define UX500_MUSB_DMA_NUM_RX_CHANNELS 8 +#define UX500_MUSB_DMA_NUM_TX_CHANNELS 8 + +struct ux500_musb_board_data { + void **dma_rx_param_array; + void **dma_tx_param_array; + u32 num_rx_channels; + u32 num_tx_channels; + bool (*dma_filter)(struct dma_chan *chan, void *filter_param); +}; + +void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg, + int *dma_tx_cfg); +#endif diff --git a/arch/arm/mach-ux500/mbox.c b/arch/arm/mach-ux500/mbox-db5500.c index 63435389c544..a4ffb9f4f461 100644 --- a/arch/arm/mach-ux500/mbox.c +++ b/arch/arm/mach-ux500/mbox-db5500.c @@ -38,7 +38,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/completion.h> -#include <mach/mbox.h> +#include <mach/mbox-db5500.h> #define MBOX_NAME "mbox" @@ -498,7 +498,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) #endif dev_info(&(mbox->pdev->dev), - "Mailbox driver with index %d initated!\n", mbox_id); + "Mailbox driver with index %d initiated!\n", mbox_id); exit: return mbox; diff --git a/arch/arm/mach-ux500/modem_irq.c b/arch/arm/mach-ux500/modem-irq-db5500.c index 3187f8871169..e1296a7447c8 100644 --- a/arch/arm/mach-ux500/modem_irq.c +++ b/arch/arm/mach-ux500/modem-irq-db5500.c @@ -12,6 +12,8 @@ #include <linux/io.h> #include <linux/slab.h> +#include <mach/id.h> + #define MODEM_INTCON_BASE_ADDR 0xBFFD3000 #define MODEM_INTCON_SIZE 0xFFF @@ -101,6 +103,9 @@ static int modem_irq_init(void) static struct irq_chip modem_irq_chip; struct modem_irq *mi; + if (!cpu_is_u5500()) + return -ENODEV; + pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n", IRQ_DB5500_MODEM); diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 9e4c678de785..4fff4d408417 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -18,39 +18,57 @@ #include <linux/io.h> #include <asm/cacheflush.h> -#include <asm/localtimer.h> #include <asm/smp_scu.h> #include <mach/hardware.h> +#include <mach/setup.h> /* * control for which core is the next to come out of the secondary * boot "holding pen" */ -volatile int __cpuinitdata pen_release = -1; +volatile int pen_release = -1; -static unsigned int __init get_core_count(void) +/* + * Write pen_release in a way that is guaranteed to be visible to all + * observers, irrespective of whether they're taking part in coherency + * or not. This is necessary for the hotplug code to work reliably. + */ +static void write_pen_release(int val) { - return scu_get_core_count(__io_address(UX500_SCU_BASE)); + pen_release = val; + smp_wmb(); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +} + +static void __iomem *scu_base_addr(void) +{ + if (cpu_is_u5500()) + return __io_address(U5500_SCU_BASE); + else if (cpu_is_u8500()) + return __io_address(U8500_SCU_BASE); + else + ux500_unknown_soc(); + + return NULL; } static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled * for us: do so */ - gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE)); + gic_secondary_init(0); /* * let the primary processor know we're out of the * pen, then head off into the C entry point */ - pen_release = -1; + write_pen_release(-1); /* * Synchronise with the boot thread. @@ -74,11 +92,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. */ - pen_release = cpu; - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1); + write_pen_release(cpu); - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { @@ -97,8 +113,14 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) static void __init wakeup_secondary(void) { - /* nobody is to be released from the pen yet */ - pen_release = -1; + void __iomem *backupram; + + if (cpu_is_u5500()) + backupram = __io_address(U5500_BACKUPRAM0_BASE); + else if (cpu_is_u8500()) + backupram = __io_address(U8500_BACKUPRAM0_BASE); + else + ux500_unknown_soc(); /* * write the address of secondary startup into the backup ram register @@ -106,15 +128,13 @@ static void __init wakeup_secondary(void) * backup ram register at offset 0x1FF0, which is what boot rom code * is waiting for. This would wake up the secondary core from WFE */ -#define U8500_CPU1_JUMPADDR_OFFSET 0x1FF4 +#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 __raw_writel(virt_to_phys(u8500_secondary_startup), - __io_address(UX500_BACKUPRAM0_BASE) + - U8500_CPU1_JUMPADDR_OFFSET); + backupram + UX500_CPU1_JUMPADDR_OFFSET); -#define U8500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 +#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 __raw_writel(0xA1FEED01, - __io_address(UX500_BACKUPRAM0_BASE) + - U8500_CPU1_WAKEMAGIC_OFFSET); + backupram + UX500_CPU1_WAKEMAGIC_OFFSET); /* make sure write buffer is drained */ mb(); @@ -126,40 +146,27 @@ static void __init wakeup_secondary(void) */ void __init smp_init_cpus(void) { - unsigned int i, ncores = get_core_count(); + void __iomem *scu_base = scu_base_addr(); + unsigned int i, ncores; - for (i = 0; i < ncores; i++) - set_cpu_possible(i, true); -} - -void __init smp_prepare_cpus(unsigned int max_cpus) -{ - unsigned int ncores = get_core_count(); - unsigned int cpu = smp_processor_id(); - int i; + ncores = scu_base ? scu_get_core_count(scu_base) : 1; /* sanity check */ - if (ncores == 0) { - printk(KERN_ERR - "U8500: strange CM count of 0? Default to 1\n"); - ncores = 1; - } - - if (ncores > num_possible_cpus()) { + if (ncores > NR_CPUS) { printk(KERN_WARNING "U8500: no. of cores (%d) greater than configured " "maximum of %d - clipping\n", - ncores, num_possible_cpus()); - ncores = num_possible_cpus(); + ncores, NR_CPUS); + ncores = NR_CPUS; } - smp_store_cpu_info(cpu); + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + int i; /* * Initialise the present map, which describes the set of CPUs @@ -168,13 +175,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - scu_enable(__io_address(UX500_SCU_BASE)); - wakeup_secondary(); - } + scu_enable(scu_base_addr()); + wakeup_secondary(); } diff --git a/arch/arm/mach-ux500/prcmu.c b/arch/arm/mach-ux500/prcmu.c index 293274d1342a..c522d26ef348 100644 --- a/arch/arm/mach-ux500/prcmu.c +++ b/arch/arm/mach-ux500/prcmu.c @@ -1,10 +1,14 @@ /* - * Copyright (C) ST Ericsson SA 2010 + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 * * License Terms: GNU General Public License v2 + * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> + * Author: Sundar Iyer <sundar.iyer@stericsson.com> * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> * - * U8500 PRCMU driver. + * U8500 PRCM Unit interface driver + * */ #include <linux/kernel.h> #include <linux/module.h> @@ -19,11 +23,26 @@ #include <mach/hardware.h> #include <mach/prcmu-regs.h> +#include <mach/prcmu-defs.h> + +/* Global var to runtime determine TCDM base for v2 or v1 */ +static __iomem void *tcdm_base; + +#define _MBOX_HEADER (tcdm_base + 0xFE8) +#define MBOX_HEADER_REQ_MB0 (_MBOX_HEADER + 0x0) + +#define REQ_MB1 (tcdm_base + 0xFD0) +#define REQ_MB5 (tcdm_base + 0xE44) -#define PRCMU_TCDM_BASE __io_address(U8500_PRCMU_TCDM_BASE) +#define REQ_MB1_ARMOPP (REQ_MB1 + 0x0) +#define REQ_MB1_APEOPP (REQ_MB1 + 0x1) +#define REQ_MB1_BOOSTOPP (REQ_MB1 + 0x2) -#define REQ_MB5 (PRCMU_TCDM_BASE + 0xE44) -#define ACK_MB5 (PRCMU_TCDM_BASE + 0xDF4) +#define ACK_MB1 (tcdm_base + 0xE04) +#define ACK_MB5 (tcdm_base + 0xDF4) + +#define ACK_MB1_CURR_ARMOPP (ACK_MB1 + 0x0) +#define ACK_MB1_CURR_APEOPP (ACK_MB1 + 0x1) #define REQ_MB5_I2C_SLAVE_OP (REQ_MB5) #define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1) @@ -33,10 +52,33 @@ #define ACK_MB5_I2C_STATUS (ACK_MB5 + 1) #define ACK_MB5_I2C_VAL (ACK_MB5 + 3) -#define I2C_WRITE(slave) ((slave) << 1) -#define I2C_READ(slave) (((slave) << 1) | BIT(0)) +#define PRCM_AVS_VARM_MAX_OPP (tcdm_base + 0x2E4) +#define PRCM_AVS_ISMODEENABLE 7 +#define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE) + +#define I2C_WRITE(slave) \ + (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0)) +#define I2C_READ(slave) \ + (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0)) #define I2C_STOP_EN BIT(3) +enum mb1_h { + MB1H_ARM_OPP = 1, + MB1H_APE_OPP, + MB1H_ARM_APE_OPP, +}; + +static struct { + struct mutex lock; + struct completion work; + struct { + u8 arm_opp; + u8 ape_opp; + u8 arm_status; + u8 ape_status; + } ack; +} mb1_transfer; + enum ack_mb5_status { I2C_WR_OK = 0x01, I2C_RD_OK = 0x02, @@ -145,6 +187,104 @@ unlock_and_return: } EXPORT_SYMBOL(prcmu_abb_write); +static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp, + enum prcmu_cpu_opp cpu_opp) +{ + bool do_ape; + bool do_arm; + int err = 0; + + do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP)); + do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP)); + + mutex_lock(&mb1_transfer.lock); + + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) + cpu_relax(); + + writeb(0, MBOX_HEADER_REQ_MB0); + writeb(cpu_opp, REQ_MB1_ARMOPP); + writeb(ape_opp, REQ_MB1_APEOPP); + writeb(0, REQ_MB1_BOOSTOPP); + writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET); + wait_for_completion(&mb1_transfer.work); + if ((do_ape) && (mb1_transfer.ack.ape_status != 0)) + err = -EIO; + if ((do_arm) && (mb1_transfer.ack.arm_status != 0)) + err = -EIO; + + mutex_unlock(&mb1_transfer.lock); + + return err; +} + +/** + * prcmu_set_ape_opp() - Set the OPP of the APE. + * @opp: The OPP to set. + * + * This function sets the OPP of the APE. + */ +int prcmu_set_ape_opp(enum prcmu_ape_opp opp) +{ + return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE); +} +EXPORT_SYMBOL(prcmu_set_ape_opp); + +/** + * prcmu_set_cpu_opp() - Set the OPP of the CPU. + * @opp: The OPP to set. + * + * This function sets the OPP of the CPU. + */ +int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp) +{ + return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp); +} +EXPORT_SYMBOL(prcmu_set_cpu_opp); + +/** + * prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU. + * @ape_opp: The APE OPP to set. + * @cpu_opp: The CPU OPP to set. + * + * This function sets the OPPs of the APE and the CPU. + */ +int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp, + enum prcmu_cpu_opp cpu_opp) +{ + return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp); +} +EXPORT_SYMBOL(prcmu_set_ape_cpu_opps); + +/** + * prcmu_get_ape_opp() - Get the OPP of the APE. + * + * This function gets the OPP of the APE. + */ +enum prcmu_ape_opp prcmu_get_ape_opp(void) +{ + return readb(ACK_MB1_CURR_APEOPP); +} +EXPORT_SYMBOL(prcmu_get_ape_opp); + +/** + * prcmu_get_cpu_opp() - Get the OPP of the CPU. + * + * This function gets the OPP of the CPU. The OPP is specified in %%. + * PRCMU_OPP_EXT is a special OPP value, not specified in %%. + */ +int prcmu_get_cpu_opp(void) +{ + return readb(ACK_MB1_CURR_ARMOPP); +} +EXPORT_SYMBOL(prcmu_get_cpu_opp); + +bool prcmu_has_arm_maxopp(void) +{ + return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK) + == PRCM_AVS_ISMODEENABLE_MASK; +} + static void read_mailbox_0(void) { writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR); @@ -152,6 +292,9 @@ static void read_mailbox_0(void) static void read_mailbox_1(void) { + mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP); + mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP); + complete(&mb1_transfer.work); writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR); } @@ -217,15 +360,35 @@ static irqreturn_t prcmu_irq_handler(int irq, void *data) return IRQ_HANDLED; } +void __init prcmu_early_init(void) +{ + if (cpu_is_u8500v11() || cpu_is_u8500ed()) { + tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1); + } else if (cpu_is_u8500v2()) { + tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); + } else { + pr_err("prcmu: Unsupported chip version\n"); + BUG(); + } +} + static int __init prcmu_init(void) { + if (cpu_is_u8500ed()) { + pr_err("prcmu: Unsupported chip version\n"); + return 0; + } + + mutex_init(&mb1_transfer.lock); + init_completion(&mb1_transfer.work); mutex_init(&mb5_transfer.lock); init_completion(&mb5_transfer.work); /* Clean up the mailbox interrupts after pre-kernel code. */ writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR); - return request_irq(IRQ_PRCMU, prcmu_irq_handler, 0, "prcmu", NULL); + return request_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 0, + "prcmu", NULL); } arch_initcall(prcmu_init); diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c new file mode 100644 index 000000000000..82e535953fd9 --- /dev/null +++ b/arch/arm/mach-ux500/usb.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> + * License terms: GNU General Public License (GPL) version 2 + */ +#include <linux/platform_device.h> +#include <linux/usb/musb.h> +#include <plat/ste_dma40.h> +#include <mach/hardware.h> +#include <mach/usb.h> + +#define MUSB_DMA40_RX_CH { \ + .mode = STEDMA40_MODE_LOGICAL, \ + .dir = STEDMA40_PERIPH_TO_MEM, \ + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, \ + .src_info.data_width = STEDMA40_WORD_WIDTH, \ + .dst_info.data_width = STEDMA40_WORD_WIDTH, \ + .src_info.psize = STEDMA40_PSIZE_LOG_16, \ + .dst_info.psize = STEDMA40_PSIZE_LOG_16, \ + } + +#define MUSB_DMA40_TX_CH { \ + .mode = STEDMA40_MODE_LOGICAL, \ + .dir = STEDMA40_MEM_TO_PERIPH, \ + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, \ + .src_info.data_width = STEDMA40_WORD_WIDTH, \ + .dst_info.data_width = STEDMA40_WORD_WIDTH, \ + .src_info.psize = STEDMA40_PSIZE_LOG_16, \ + .dst_info.psize = STEDMA40_PSIZE_LOG_16, \ + } + +static struct stedma40_chan_cfg musb_dma_rx_ch[UX500_MUSB_DMA_NUM_RX_CHANNELS] + = { + MUSB_DMA40_RX_CH, + MUSB_DMA40_RX_CH, + MUSB_DMA40_RX_CH, + MUSB_DMA40_RX_CH, + MUSB_DMA40_RX_CH, + MUSB_DMA40_RX_CH, + MUSB_DMA40_RX_CH, + MUSB_DMA40_RX_CH +}; + +static struct stedma40_chan_cfg musb_dma_tx_ch[UX500_MUSB_DMA_NUM_TX_CHANNELS] + = { + MUSB_DMA40_TX_CH, + MUSB_DMA40_TX_CH, + MUSB_DMA40_TX_CH, + MUSB_DMA40_TX_CH, + MUSB_DMA40_TX_CH, + MUSB_DMA40_TX_CH, + MUSB_DMA40_TX_CH, + MUSB_DMA40_TX_CH, +}; + +static void *ux500_dma_rx_param_array[UX500_MUSB_DMA_NUM_RX_CHANNELS] = { + &musb_dma_rx_ch[0], + &musb_dma_rx_ch[1], + &musb_dma_rx_ch[2], + &musb_dma_rx_ch[3], + &musb_dma_rx_ch[4], + &musb_dma_rx_ch[5], + &musb_dma_rx_ch[6], + &musb_dma_rx_ch[7] +}; + +static void *ux500_dma_tx_param_array[UX500_MUSB_DMA_NUM_TX_CHANNELS] = { + &musb_dma_tx_ch[0], + &musb_dma_tx_ch[1], + &musb_dma_tx_ch[2], + &musb_dma_tx_ch[3], + &musb_dma_tx_ch[4], + &musb_dma_tx_ch[5], + &musb_dma_tx_ch[6], + &musb_dma_tx_ch[7] +}; + +static struct ux500_musb_board_data musb_board_data = { + .dma_rx_param_array = ux500_dma_rx_param_array, + .dma_tx_param_array = ux500_dma_tx_param_array, + .num_rx_channels = UX500_MUSB_DMA_NUM_RX_CHANNELS, + .num_tx_channels = UX500_MUSB_DMA_NUM_TX_CHANNELS, + .dma_filter = stedma40_filter, +}; + +static u64 ux500_musb_dmamask = DMA_BIT_MASK(32); + +static struct musb_hdrc_config musb_hdrc_config = { + .multipoint = true, + .dyn_fifo = true, + .num_eps = 16, + .ram_bits = 16, +}; + +static struct musb_hdrc_platform_data musb_platform_data = { +#if defined(CONFIG_USB_MUSB_OTG) + .mode = MUSB_OTG, +#elif defined(CONFIG_USB_MUSB_PERIPHERAL) + .mode = MUSB_PERIPHERAL, +#else /* defined(CONFIG_USB_MUSB_HOST) */ + .mode = MUSB_HOST, +#endif + .config = &musb_hdrc_config, + .board_data = &musb_board_data, +}; + +static struct resource usb_resources[] = { + [0] = { + .name = "usb-mem", + .flags = IORESOURCE_MEM, + }, + + [1] = { + .name = "mc", /* hard-coded in musb */ + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device ux500_musb_device = { + .name = "musb-ux500", + .id = 0, + .dev = { + .platform_data = &musb_platform_data, + .dma_mask = &ux500_musb_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(usb_resources), + .resource = usb_resources, +}; + +static inline void ux500_usb_dma_update_rx_ch_config(int *src_dev_type) +{ + u32 idx; + + for (idx = 0; idx < UX500_MUSB_DMA_NUM_RX_CHANNELS; idx++) + musb_dma_rx_ch[idx].src_dev_type = src_dev_type[idx]; +} + +static inline void ux500_usb_dma_update_tx_ch_config(int *dst_dev_type) +{ + u32 idx; + + for (idx = 0; idx < UX500_MUSB_DMA_NUM_TX_CHANNELS; idx++) + musb_dma_tx_ch[idx].dst_dev_type = dst_dev_type[idx]; +} + +void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg, + int *dma_tx_cfg) +{ + ux500_musb_device.resource[0].start = base; + ux500_musb_device.resource[0].end = base + SZ_64K - 1; + ux500_musb_device.resource[1].start = irq; + ux500_musb_device.resource[1].end = irq; + + ux500_usb_dma_update_rx_ch_config(dma_rx_cfg); + ux500_usb_dma_update_tx_ch_config(dma_tx_cfg); + + platform_device_register(&ux500_musb_device); +} |