diff options
Diffstat (limited to 'arch/arm/mach-omap2')
148 files changed, 27586 insertions, 3998 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 841ae21..3924ddb 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -45,12 +45,13 @@ config ARCH_OMAP4 select CPU_V7 select ARM_GIC select LOCAL_TIMERS if SMP - select PL310_ERRATA_588369 - select PL310_ERRATA_727915 + select PL310_ERRATA_588369 if CONFIG_CACHE_L2X0 + select PL310_ERRATA_727915 if CONFIG_CACHE_L2X0 select ARM_ERRATA_720789 select ARCH_HAS_OPP select PM_OPP if PM select USB_ARCH_HAS_EHCI + select ARCH_HAS_BARRIERS comment "OMAP Core Type" depends on ARCH_OMAP2 @@ -314,6 +315,7 @@ config MACH_OMAP_4430SDP select OMAP_PACKAGE_CBL select OMAP_PACKAGE_CBS select REGULATOR_FIXED_VOLTAGE + select OMAP_TPS6236X config MACH_OMAP4_PANDA bool "OMAP4 Panda Board" @@ -343,6 +345,42 @@ config OMAP3_SDRC_AC_TIMING wish to say no. Selecting yes without understanding what is going on could result in system crashes; +config OMAP_TPS6236X + bool + +config OMAP_ALLOW_OSWR + bool "Enable Open Switch Retention" + depends on ARCH_OMAP4 + default n + help + Select this option to enable OSWR support. + Which means the Logic of power domains can be lost now + unlike the CSWR wherein the logic is retained + +config OMAP_FIQ_DEBUGGER + bool "Enable the serial FIQ debugger on OMAP" + default y + select FIQ_DEBUGGER + help + Enables the serial FIQ debugger on OMAP" + +config OMAP4_PPA_CPU1_ONLINE_BUG + bool "Enable Support for CPU1 ONLINE WA for OSWR/OFF" + depends on ARCH_OMAP4 + depends on OMAP_ALLOW_OSWR + default y + help + If an non GP OMAP4 device is used and PPA revision is < v1.7.3, + the device does not perform the memory maintenance and TLB sync + operations required before releasing CPU1 to HLOS. This results + in crash while resuming from OFF mode. + + Disable this option *ONLY IF* you meet the minimum PPA version + requirement. + + If, on the other hand, you do not understand the change, leave the + default as enabled. + endmenu endif diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index b148077..aa42baf 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -4,7 +4,7 @@ # Common support obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o \ - common.o gpio.o dma.o wd_timer.o + common.o gpio.o dma.o wd_timer.o omap_pmic.o dmtimer.o omap-2-3-common = irq.o sdrc.o hwmod-common = omap_hwmod.o \ @@ -15,16 +15,20 @@ clock-common = clock.o clock_common_data.o \ obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) +obj-$(CONFIG_ARCH_OMAP4) += emif.o lpddr2_jedec_data.o lpddr2_elpida_data.o obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o obj-$(CONFIG_TWL4030_CORE) += omap_twl.o +obj-$(CONFIG_OMAP_TPS6236X) += omap_tps6236x.o +obj-$(CONFIG_OMAP_TEMP_SENSOR) +=temp_sensor_device.o # SMP support ONLY available for OMAP4 obj-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o obj-$(CONFIG_LOCAL_TIMERS) += timer-mpu.o obj-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o -obj-$(CONFIG_ARCH_OMAP4) += omap44xx-smc.o omap4-common.o +obj-$(CONFIG_ARCH_OMAP4) += omap44xx-smc.o omap4-common.o \ + omap-wakeupgen.o plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a$(plus_sec) @@ -56,19 +60,29 @@ obj-$(CONFIG_ARCH_OMAP3) += opp3xxx_data.o obj-$(CONFIG_ARCH_OMAP4) += opp4xxx_data.o endif +# CPUFREQ driver +obj-$(CONFIG_CPU_FREQ) += omap2plus-cpufreq.o + # Power Management ifeq ($(CONFIG_PM),y) obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o \ cpuidle34xx.o -obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o +obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o \ + omap4-mpuss-lowpower.o sleep44xx.o \ + cpuidle44xx.o resetreason.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o +ifeq ($(CONFIG_PM_DEBUG),y) +obj-$(CONFIG_ARCH_OMAP4) += prcm-debug.o +endif obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o +obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS1P5) += smartreflex-class1p5.o AFLAGS_sleep24xx.o :=-Wa,-march=armv6 AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_sleep44xx.o :=-Wa,-march=armv7-a$(plus_sec) ifeq ($(CONFIG_PM_VERBOSE),y) CFLAGS_pm_bus.o += -DDEBUG @@ -86,16 +100,19 @@ obj-$(CONFIG_ARCH_OMAP3) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \ obj-$(CONFIG_ARCH_OMAP4) += prcm.o cm2xxx_3xxx.o cminst44xx.o \ cm44xx.o prcm_mpu44xx.o \ prminst44xx.o vc44xx_data.o \ - vp44xx_data.o + vp44xx_data.o omap4-sar.o # OMAP voltage domains ifeq ($(CONFIG_PM),y) -voltagedomain-common := voltage.o -obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) +voltagedomain-common := voltage.o vc.o vp.o +obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) \ + voltagedomains2xxx_data.o obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) \ - voltagedomains3xxx_data.o + voltagedomains3xxx_data.o \ + ldo.o ldo3xxx_data.o dvfs.o obj-$(CONFIG_ARCH_OMAP4) += $(voltagedomain-common) \ - voltagedomains44xx_data.o + voltagedomains44xx_data.o \ + ldo.o ldo4xxx_data.o dvfs.o endif # OMAP powerdomain framework @@ -157,13 +174,13 @@ obj-$(CONFIG_OMAP3_EMU) += emu.o obj-$(CONFIG_ARCH_OMAP3) += omap_l3_smx.o obj-$(CONFIG_ARCH_OMAP4) += omap_l3_noc.o +# LDO stuff +obj-$(CONFIG_ARCH_OMAP4) += omap4_trim_quirks.o + obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o mailbox_mach-objs := mailbox.o -obj-$(CONFIG_OMAP_IOMMU) += iommu2.o - -iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o -obj-y += $(iommu-m) $(iommu-y) +obj-$(CONFIG_OMAP_IOMMU) += iommu2.o omap-iommu.o i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o obj-y += $(i2c-omap-m) $(i2c-omap-y) @@ -241,6 +258,8 @@ obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \ obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o \ omap_phy_internal.o \ +obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o + obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o obj-$(CONFIG_MACH_SBC3530) += board-omap3stalker.o \ @@ -270,3 +289,8 @@ disp-$(CONFIG_OMAP2_DSS) := display.o obj-y += $(disp-m) $(disp-y) obj-y += common-board-devices.o + +obj-$(CONFIG_OMAP_REMOTE_PROC) += remoteproc.o +obj-$(CONFIG_OMAP_HSI_DEVICE) += omap_hsi.o +obj-$(CONFIG_ARCH_OMAP4) += omap_dmm.o +obj-$(CONFIG_OMAP_FIQ_DEBUGGER) += omap_fiq_debugger.o diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 5dac974..4e2baf7 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -553,106 +553,8 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = { static struct omap_board_mux board_mux[] __initdata = { { .reg_offset = OMAP_MUX_TERMINATOR }, }; - -static struct omap_device_pad serial1_pads[] __initdata = { - /* - * Note that off output enable is an active low - * signal. So setting this means pin is a - * input enabled in off mode - */ - OMAP_MUX_STATIC("uart1_cts.uart1_cts", - OMAP_PIN_INPUT | - OMAP_PIN_OFF_INPUT_PULLDOWN | - OMAP_OFFOUT_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart1_rts.uart1_rts", - OMAP_PIN_OUTPUT | - OMAP_OFF_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart1_rx.uart1_rx", - OMAP_PIN_INPUT | - OMAP_PIN_OFF_INPUT_PULLDOWN | - OMAP_OFFOUT_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart1_tx.uart1_tx", - OMAP_PIN_OUTPUT | - OMAP_OFF_EN | - OMAP_MUX_MODE0), -}; - -static struct omap_device_pad serial2_pads[] __initdata = { - OMAP_MUX_STATIC("uart2_cts.uart2_cts", - OMAP_PIN_INPUT_PULLUP | - OMAP_PIN_OFF_INPUT_PULLDOWN | - OMAP_OFFOUT_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_rts.uart2_rts", - OMAP_PIN_OUTPUT | - OMAP_OFF_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_rx.uart2_rx", - OMAP_PIN_INPUT | - OMAP_PIN_OFF_INPUT_PULLDOWN | - OMAP_OFFOUT_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_tx.uart2_tx", - OMAP_PIN_OUTPUT | - OMAP_OFF_EN | - OMAP_MUX_MODE0), -}; - -static struct omap_device_pad serial3_pads[] __initdata = { - OMAP_MUX_STATIC("uart3_cts_rctx.uart3_cts_rctx", - OMAP_PIN_INPUT_PULLDOWN | - OMAP_PIN_OFF_INPUT_PULLDOWN | - OMAP_OFFOUT_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_rts_sd.uart3_rts_sd", - OMAP_PIN_OUTPUT | - OMAP_OFF_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_rx_irrx.uart3_rx_irrx", - OMAP_PIN_INPUT | - OMAP_PIN_OFF_INPUT_PULLDOWN | - OMAP_OFFOUT_EN | - OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_tx_irtx.uart3_tx_irtx", - OMAP_PIN_OUTPUT | - OMAP_OFF_EN | - OMAP_MUX_MODE0), -}; - -static struct omap_board_data serial1_data __initdata = { - .id = 0, - .pads = serial1_pads, - .pads_cnt = ARRAY_SIZE(serial1_pads), -}; - -static struct omap_board_data serial2_data __initdata = { - .id = 1, - .pads = serial2_pads, - .pads_cnt = ARRAY_SIZE(serial2_pads), -}; - -static struct omap_board_data serial3_data __initdata = { - .id = 2, - .pads = serial3_pads, - .pads_cnt = ARRAY_SIZE(serial3_pads), -}; - -static inline void board_serial_init(void) -{ - omap_serial_init_port(&serial1_data); - omap_serial_init_port(&serial2_data); - omap_serial_init_port(&serial3_data); -} #else #define board_mux NULL - -static inline void board_serial_init(void) -{ - omap_serial_init(); -} #endif /* @@ -789,7 +691,7 @@ static void __init omap_3430sdp_init(void) else gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV1; omap_ads7846_init(1, gpio_pendown, 310, NULL); - board_serial_init(); + omap_serial_init(); usb_musb_init(NULL); board_smc91x_init(); board_flash_init(sdp_flash_partitions, chip_sel_3430, 0); diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 14a5971..8396ac8 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -24,9 +24,14 @@ #include <linux/regulator/machine.h> #include <linux/leds.h> #include <linux/leds_pwm.h> +#include <linux/memblock.h> #include <mach/hardware.h> #include <mach/omap4-common.h> +#include <mach/emif.h> +#include <mach/lpddr2-elpida.h> +#include <mach/dmm.h> + #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -36,13 +41,16 @@ #include <plat/usb.h> #include <plat/mmc.h> #include <plat/omap4-keypad.h> +#include <plat/remoteproc.h> #include <video/omapdss.h> +#include <video/omap-panel-nokia-dsi.h> #include "mux.h" #include "hsmmc.h" #include "timer-gp.h" #include "control.h" #include "common-board-devices.h" +#include "pm.h" #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON 48 @@ -51,6 +59,20 @@ #define OMAP4_SFH7741_ENABLE_GPIO 188 #define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define LCD_BL_GPIO 27 /* LCD Backlight GPIO */ +/* PWM2 and TOGGLE3 register offsets */ +#define LED_PWM2ON 0x03 +#define LED_PWM2OFF 0x04 +#define TWL6030_TOGGLE3 0x92 + +#define TPS62361_GPIO 7 + +#define PHYS_ADDR_SMC_SIZE (SZ_1M * 3) +#define PHYS_ADDR_SMC_MEM (0x80000000 + SZ_1G - PHYS_ADDR_SMC_SIZE) +#define OMAP_ION_HEAP_SECURE_INPUT_SIZE (SZ_1M * 90) +#define PHYS_ADDR_DUCATI_SIZE (SZ_1M * 105) +#define PHYS_ADDR_DUCATI_MEM (PHYS_ADDR_SMC_MEM - PHYS_ADDR_DUCATI_SIZE - \ + OMAP_ION_HEAP_SECURE_INPUT_SIZE) #define HDMI_GPIO_HPD 63 /* Hotplug detect */ static const int sdp4430_keymap[] = { @@ -272,24 +294,13 @@ static int __init omap_ethernet_init(void) return status; } -static struct platform_device sdp4430_lcd_device = { - .name = "sdp4430_lcd", - .id = -1, -}; - static struct platform_device *sdp4430_devices[] __initdata = { - &sdp4430_lcd_device, &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, &sdp4430_leds_pwm, }; -static struct omap_lcd_config sdp4430_lcd_config __initdata = { - .ctrl_name = "internal", -}; - static struct omap_board_config_kernel sdp4430_config[] __initdata = { - { OMAP_TAG_LCD, &sdp4430_lcd_config }, }; static void __init omap_4430sdp_init_early(void) @@ -345,6 +356,10 @@ static struct regulator_consumer_supply sdp4430_vmmc_supply[] = { .dev_name = "omap_hsmmc.0", }, }; +static struct regulator_consumer_supply sdp4430_vcxio_supply[] = { + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dss"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"), +}; static int omap4_twl6030_hsmmc_late_init(struct device *dev) { @@ -491,7 +506,10 @@ static struct regulator_init_data sdp4430_vcxio = { | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + .always_on = true, }, + .num_consumer_supplies = ARRAY_SIZE(sdp4430_vcxio_supply), + .consumer_supplies = sdp4430_vcxio_supply, }; static struct regulator_init_data sdp4430_vdac = { @@ -577,6 +595,76 @@ static void __init omap_sfh7741prox_init(void) __func__, OMAP4_SFH7741_ENABLE_GPIO, error); } +static int dsi1_panel_set_backlight(struct omap_dss_device *dssdev, int level) +{ + int r; + + r = twl_i2c_write_u8(TWL_MODULE_PWM, 0x7F, LED_PWM2OFF); + if (r) + return r; + + if (level > 1) { + if (level == 255) + level = 0x7F; + else + level = (~(level/2)) & 0x7F; + + r = twl_i2c_write_u8(TWL_MODULE_PWM, level, LED_PWM2ON); + if (r) + return r; + r = twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x30, TWL6030_TOGGLE3); + if (r) + return r; + } else if (level <= 1) { + r = twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x08, TWL6030_TOGGLE3); + if (r) + return r; + r = twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x28, TWL6030_TOGGLE3); + if (r) + return r; + r = twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x00, TWL6030_TOGGLE3); + if (r) + return r; + } + + return 0; +} + +static struct nokia_dsi_panel_data dsi1_panel; + +static void sdp4430_lcd_init(void) +{ + u32 reg; + int status; + + /* Enable 3 lanes in DSI1 module, disable pull down */ + reg = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY); + reg &= ~OMAP4_DSI1_LANEENABLE_MASK; + reg |= 0x7 << OMAP4_DSI1_LANEENABLE_SHIFT; + reg &= ~OMAP4_DSI1_PIPD_MASK; + reg |= 0x7 << OMAP4_DSI1_PIPD_SHIFT; + omap4_ctrl_pad_writel(reg, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY); + + /* Panel Taal reset and backlight GPIO init */ + status = gpio_request_one(dsi1_panel.reset_gpio, GPIOF_DIR_OUT, + "lcd_reset_gpio"); + if (status) + pr_err("%s: Could not get lcd_reset_gpio\n", __func__); + + if (dsi1_panel.use_ext_te) { + status = omap_mux_init_signal("gpmc_ncs4.gpio_101", + OMAP_PIN_INPUT_PULLUP); + if (status) + pr_err("%s: Could not get ext_te gpio\n", __func__); + } + + status = gpio_request_one(LCD_BL_GPIO, GPIOF_DIR_OUT, "lcd_bl_gpio"); + if (status) + pr_err("%s: Could not get lcd_bl_gpio\n", __func__); + + gpio_set_value(LCD_BL_GPIO, 0); +} + static void sdp4430_hdmi_mux_init(void) { omap_mux_init_signal("hdmi_cec", @@ -610,6 +698,52 @@ static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev) gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios)); } +static struct nokia_dsi_panel_data dsi1_panel = { + .name = "taal", + .reset_gpio = 102, + .use_ext_te = false, + .ext_te_gpio = 101, + .esd_interval = 0, + .set_backlight = dsi1_panel_set_backlight, +}; + +static struct omap_dss_device sdp4430_lcd_device = { + .name = "lcd", + .driver_name = "taal", + .type = OMAP_DISPLAY_TYPE_DSI, + .data = &dsi1_panel, + .phy.dsi = { + .clk_lane = 1, + .clk_pol = 0, + .data1_lane = 2, + .data1_pol = 0, + .data2_lane = 3, + .data2_pol = 0, + }, + + .clocks = { + .dispc = { + .channel = { + .lck_div = 1, /* Logic Clock = 172.8 MHz */ + .pck_div = 5, /* Pixel Clock = 34.56 MHz */ + .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, + }, + .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, + }, + + .dsi = { + .regn = 16, /* Fint = 2.4 MHz */ + .regm = 180, /* DDR Clock = 216 MHz */ + .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */ + .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */ + + .lp_clk_div = 10, /* LP Clock = 8.64 MHz */ + .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, + }, + }, + .channel = OMAP_DSS_CHANNEL_LCD, +}; + static struct omap_dss_hdmi_data sdp4430_hdmi_data = { .hpd_gpio = HDMI_GPIO_HPD, }; @@ -625,17 +759,19 @@ static struct omap_dss_device sdp4430_hdmi_device = { }; static struct omap_dss_device *sdp4430_dss_devices[] = { + &sdp4430_lcd_device, &sdp4430_hdmi_device, }; static struct omap_dss_board_info sdp4430_dss_data = { .num_devices = ARRAY_SIZE(sdp4430_dss_devices), .devices = sdp4430_dss_devices, - .default_device = &sdp4430_hdmi_device, + .default_device = &sdp4430_lcd_device, }; void omap_4430sdp_display_init(void) { + sdp4430_lcd_init(); sdp4430_hdmi_mux_init(); omap_display_init(&sdp4430_dss_data); @@ -650,67 +786,28 @@ static struct omap_board_mux board_mux[] __initdata = { { .reg_offset = OMAP_MUX_TERMINATOR }, }; -static struct omap_device_pad serial2_pads[] __initdata = { - OMAP_MUX_STATIC("uart2_cts.uart2_cts", - OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_rts.uart2_rts", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_rx.uart2_rx", - OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_tx.uart2_tx", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), -}; - -static struct omap_device_pad serial3_pads[] __initdata = { - OMAP_MUX_STATIC("uart3_cts_rctx.uart3_cts_rctx", - OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_rts_sd.uart3_rts_sd", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_rx_irrx.uart3_rx_irrx", - OMAP_PIN_INPUT | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_tx_irtx.uart3_tx_irtx", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), -}; - -static struct omap_device_pad serial4_pads[] __initdata = { - OMAP_MUX_STATIC("uart4_rx.uart4_rx", - OMAP_PIN_INPUT | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart4_tx.uart4_tx", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), -}; - -static struct omap_board_data serial2_data __initdata = { - .id = 1, - .pads = serial2_pads, - .pads_cnt = ARRAY_SIZE(serial2_pads), -}; - -static struct omap_board_data serial3_data __initdata = { - .id = 2, - .pads = serial3_pads, - .pads_cnt = ARRAY_SIZE(serial3_pads), -}; - -static struct omap_board_data serial4_data __initdata = { - .id = 3, - .pads = serial4_pads, - .pads_cnt = ARRAY_SIZE(serial4_pads), +/* + * LPDDR2 Configeration Data: + * The memory organisation is as below : + * EMIF1 - CS0 - 2 Gb + * CS1 - 2 Gb + * EMIF2 - CS0 - 2 Gb + * CS1 - 2 Gb + * -------------------- + * TOTAL - 8 Gb + * + * Same devices installed on EMIF1 and EMIF2 + */ +static __initdata struct emif_device_details emif_devices = { + .cs0_device = &lpddr2_elpida_2G_S4_dev, + .cs1_device = &lpddr2_elpida_2G_S4_dev }; -static inline void board_serial_init(void) +static inline void __init board_serial_init(void) { - struct omap_board_data bdata; - bdata.flags = 0; - bdata.pads = NULL; - bdata.pads_cnt = 0; - bdata.id = 0; - /* pass dummy data for UART1 */ - omap_serial_init_port(&bdata); - - omap_serial_init_port(&serial2_data); - omap_serial_init_port(&serial3_data); - omap_serial_init_port(&serial4_data); + omap_serial_init(); } + #else #define board_mux NULL @@ -729,6 +826,8 @@ static void __init omap_4430sdp_init(void) package = OMAP_PACKAGE_CBL; omap4_mux_init(board_mux, NULL, package); + omap_emif_setup_device_details(&emif_devices, &emif_devices); + omap_board_config = sdp4430_config; omap_board_config_size = ARRAY_SIZE(sdp4430_config); @@ -753,7 +852,16 @@ static void __init omap_4430sdp_init(void) if (status) pr_err("Keypad initialization failed: %d\n", status); + omap_dmm_init(); omap_4430sdp_display_init(); + + if (cpu_is_omap446x()) { + /* Vsel0 = gpio, vsel1 = gnd */ + status = omap_tps6236x_board_setup(true, TPS62361_GPIO, -1, + OMAP_PIN_OFF_OUTPUT_HIGH, -1); + if (status) + pr_err("TPS62361 initialization failed: %d\n", status); + } } static void __init omap_4430sdp_map_io(void) @@ -762,10 +870,22 @@ static void __init omap_4430sdp_map_io(void) omap44xx_map_common_io(); } +static void __init omap_4430sdp_reserve(void) +{ + /* do the static reservations first */ + memblock_remove(PHYS_ADDR_SMC_MEM, PHYS_ADDR_SMC_SIZE); + memblock_remove(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE); + /* ipu needs to recognize secure input buffer area as well */ + omap_ipu_set_static_mempool(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE + + OMAP_ION_HEAP_SECURE_INPUT_SIZE); + + omap_reserve(); +} + MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board") /* Maintainer: Santosh Shilimkar - Texas Instruments Inc */ .boot_params = 0x80000100, - .reserve = omap_reserve, + .reserve = omap_4430sdp_reserve, .map_io = omap_4430sdp_map_io, .init_early = omap_4430sdp_init_early, .init_irq = gic_init_irq, diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 8d74318..5ab626a 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -656,15 +656,15 @@ static inline void board_serial_init(void) bdata.pads_cnt = 0; bdata.id = 0; - omap_serial_init_port(&bdata); + omap_serial_init_port(&bdata, NULL); bdata.id = 1; - omap_serial_init_port(&bdata); + omap_serial_init_port(&bdata, NULL); bdata.id = 2; bdata.pads = serial2_pads; bdata.pads_cnt = ARRAY_SIZE(serial2_pads); - omap_serial_init_port(&bdata); + omap_serial_init_port(&bdata, NULL); } #else diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 107dfc3..5f42052 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -28,9 +28,14 @@ #include <linux/regulator/machine.h> #include <linux/regulator/fixed.h> #include <linux/wl12xx.h> +#include <linux/memblock.h> #include <mach/hardware.h> #include <mach/omap4-common.h> +#include <mach/emif.h> +#include <mach/lpddr2-elpida.h> +#include <mach/dmm.h> + #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -40,6 +45,7 @@ #include <plat/common.h> #include <plat/usb.h> #include <plat/mmc.h> +#include <plat/remoteproc.h> #include <video/omap-panel-generic-dpi.h> #include "timer-gp.h" @@ -56,6 +62,14 @@ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ #define HDMI_GPIO_HPD 63 /* Hotplug detect */ + +#define PHYS_ADDR_SMC_SIZE (SZ_1M * 3) +#define PHYS_ADDR_SMC_MEM (0x80000000 + SZ_1G - PHYS_ADDR_SMC_SIZE) +#define OMAP_ION_HEAP_SECURE_INPUT_SIZE (SZ_1M * 90) +#define PHYS_ADDR_DUCATI_SIZE (SZ_1M * 105) +#define PHYS_ADDR_DUCATI_MEM (PHYS_ADDR_SMC_MEM - PHYS_ADDR_DUCATI_SIZE - \ + OMAP_ION_HEAP_SECURE_INPUT_SIZE) + /* wl127x BT, FM, GPS connectivity chip */ static int wl1271_gpios[] = {46, -1, -1}; static struct platform_device wl1271_device = { @@ -152,7 +166,11 @@ static void __init omap4_ehci_init(void) static struct omap_musb_board_data musb_board_data = { .interface_type = MUSB_INTERFACE_UTMI, +#ifdef CONFIG_USB_GADGET_MUSB_HDRC + .mode = MUSB_PERIPHERAL, +#else .mode = MUSB_OTG, +#endif .power = 100, }; @@ -381,6 +399,24 @@ static struct regulator_init_data omap4_panda_clk32kg = { }, }; +static void omap4_audio_conf(void) +{ + /* twl6040 naudint */ + omap_mux_init_signal("sys_nirq2.sys_nirq2", \ + OMAP_PIN_INPUT_PULLUP); +} + +static struct twl4030_codec_audio_data twl6040_audio = { + /* Add audio only data */ +}; + +static struct twl4030_codec_data twl6040_codec = { + .audio = &twl6040_audio, + .audpwron_gpio = 127, + .naudint_irq = OMAP44XX_IRQ_SYS_2N, + .irq_base = TWL6040_CODEC_IRQ_BASE, +}; + static struct twl4030_platform_data omap4_panda_twldata = { .irq_base = TWL6030_IRQ_BASE, .irq_end = TWL6030_IRQ_END, @@ -396,6 +432,9 @@ static struct twl4030_platform_data omap4_panda_twldata = { .vaux3 = &omap4_panda_vaux3, .clk32kg = &omap4_panda_clk32kg, .usb = &omap4_usbphy_data, + + /* children */ + .codec = &twl6040_codec, }; /* @@ -498,71 +537,14 @@ static struct omap_board_mux board_mux[] __initdata = { { .reg_offset = OMAP_MUX_TERMINATOR }, }; -static struct omap_device_pad serial2_pads[] __initdata = { - OMAP_MUX_STATIC("uart2_cts.uart2_cts", - OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_rts.uart2_rts", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_rx.uart2_rx", - OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart2_tx.uart2_tx", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), -}; - -static struct omap_device_pad serial3_pads[] __initdata = { - OMAP_MUX_STATIC("uart3_cts_rctx.uart3_cts_rctx", - OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_rts_sd.uart3_rts_sd", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_rx_irrx.uart3_rx_irrx", - OMAP_PIN_INPUT | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart3_tx_irtx.uart3_tx_irtx", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), -}; - -static struct omap_device_pad serial4_pads[] __initdata = { - OMAP_MUX_STATIC("uart4_rx.uart4_rx", - OMAP_PIN_INPUT | OMAP_MUX_MODE0), - OMAP_MUX_STATIC("uart4_tx.uart4_tx", - OMAP_PIN_OUTPUT | OMAP_MUX_MODE0), -}; - -static struct omap_board_data serial2_data __initdata = { - .id = 1, - .pads = serial2_pads, - .pads_cnt = ARRAY_SIZE(serial2_pads), -}; - -static struct omap_board_data serial3_data __initdata = { - .id = 2, - .pads = serial3_pads, - .pads_cnt = ARRAY_SIZE(serial3_pads), -}; - -static struct omap_board_data serial4_data __initdata = { - .id = 3, - .pads = serial4_pads, - .pads_cnt = ARRAY_SIZE(serial4_pads), -}; - -static inline void board_serial_init(void) +static inline void __init board_serial_init(void) { - struct omap_board_data bdata; - bdata.flags = 0; - bdata.pads = NULL; - bdata.pads_cnt = 0; - bdata.id = 0; - /* pass dummy data for UART1 */ - omap_serial_init_port(&bdata); - - omap_serial_init_port(&serial2_data); - omap_serial_init_port(&serial3_data); - omap_serial_init_port(&serial4_data); + omap_serial_init(); } #else #define board_mux NULL -static inline void board_serial_init(void) +static inline void __init board_serial_init(void) { omap_serial_init(); } @@ -584,7 +566,7 @@ static void omap4_panda_disable_dvi(struct omap_dss_device *dssdev) /* Using generic display panel */ static struct panel_generic_dpi_data omap4_dvi_panel = { - .name = "generic", + .name = "generic_720p", .platform_enable = omap4_panda_enable_dvi, .platform_disable = omap4_panda_disable_dvi, }; @@ -671,6 +653,23 @@ static struct omap_dss_board_info omap4_panda_dss_data = { .default_device = &omap4_panda_dvi_device, }; +/* + * LPDDR2 Configeration Data: + * The memory organisation is as below : + * EMIF1 - CS0 - 2 Gb + * CS1 - 2 Gb + * EMIF2 - CS0 - 2 Gb + * CS1 - 2 Gb + * -------------------- + * TOTAL - 8 Gb + * + * Same devices installed on EMIF1 and EMIF2 + */ +static __initdata struct emif_device_details emif_devices = { + .cs0_device = &lpddr2_elpida_2G_S4_dev, + .cs1_device = &lpddr2_elpida_2G_S4_dev +}; + void omap4_panda_display_init(void) { int r; @@ -687,10 +686,14 @@ void omap4_panda_display_init(void) omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN); } +extern void __init omap4_panda_android_init(void); + static void __init omap4_panda_init(void) { int package = OMAP_PACKAGE_CBS; + omap_emif_setup_device_details(&emif_devices, &emif_devices); + if (omap_rev() == OMAP4430_REV_ES1_0) package = OMAP_PACKAGE_CBL; omap4_mux_init(board_mux, NULL, package); @@ -699,13 +702,23 @@ static void __init omap4_panda_init(void) pr_err("error setting wl12xx data\n"); omap4_panda_i2c_init(); + omap4_audio_conf(); platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices)); - platform_device_register(&omap_vwlan_device); +/* + * This is temporaray. With WLAN regsitering, we see that UART2 is not + * idling on panda and CORE RET is not happening. So removing this FTM. + * Later will be enabled. + * + * platform_device_register(&omap_vwlan_device); + */ board_serial_init(); omap4_twl6030_hsmmc_init(mmc); omap4_ehci_init(); usb_musb_init(&musb_board_data); + + omap_dmm_init(); omap4_panda_display_init(); + } static void __init omap4_panda_map_io(void) @@ -714,10 +727,22 @@ static void __init omap4_panda_map_io(void) omap44xx_map_common_io(); } +static void __init omap4_panda_reserve(void) +{ + /* do the static reservations first */ + memblock_remove(PHYS_ADDR_SMC_MEM, PHYS_ADDR_SMC_SIZE); + memblock_remove(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE); + /* ipu needs to recognize secure input buffer area as well */ + omap_ipu_set_static_mempool(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE + + OMAP_ION_HEAP_SECURE_INPUT_SIZE); + + omap_reserve(); +} + MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board") /* Maintainer: David Anders - Texas Instruments Inc */ .boot_params = 0x80000100, - .reserve = omap_reserve, + .reserve = omap4_panda_reserve, .map_io = omap4_panda_map_io, .init_early = omap4_panda_init_early, .init_irq = gic_init_irq, diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index bcffee0..a7e78e4 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -292,12 +292,14 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) for (n = dd->min_divider; n <= dd->max_divider; n++) { - /* Is the (input clk, divider) pair valid for the DPLL? */ - r = _dpll_test_fint(clk, n); - if (r == DPLL_FINT_UNDERFLOW) - break; - else if (r == DPLL_FINT_INVALID) - continue; + if (cpu_is_omap34xx()) { + /* Is the (input clk, divider)pair valid for the DPLL?*/ + r = _dpll_test_fint(clk, n); + if (r == DPLL_FINT_UNDERFLOW) + break; + else if (r == DPLL_FINT_INVALID) + continue; + } /* Compute the scaled DPLL multiplier, based on the divider */ m = scaled_rt_rp * n; diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 180299e..1334f59 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -32,6 +32,7 @@ #include "clock.h" #include "cm2xxx_3xxx.h" +#include "cm44xx.h" #include "cm-regbits-24xx.h" #include "cm-regbits-34xx.h" @@ -43,6 +44,11 @@ u8 cpu_mask; /* Private functions */ +static void _omap4_module_wait_ready(struct clk *clk) +{ + omap4_cm_wait_module_ready(clk->enable_reg); +} + /** * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE * @clk: struct clk * belonging to the module @@ -190,8 +196,12 @@ int omap2_dflt_clk_enable(struct clk *clk) __raw_writel(v, clk->enable_reg); v = __raw_readl(clk->enable_reg); /* OCP barrier */ - if (clk->ops->find_idlest) - _omap2_module_wait_ready(clk); + if (clk->ops->find_idlest) { + if (cpu_is_omap44xx()) + _omap4_module_wait_ready(clk); + else + _omap2_module_wait_ready(clk); + } return 0; } @@ -219,6 +229,12 @@ void omap2_dflt_clk_disable(struct clk *clk) /* No OCP barrier needed here since it is a disable operation */ } +const struct clkops clkops_omap4_dflt_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap2_clk_dflt_find_idlest, +}; + const struct clkops clkops_omap2_dflt_wait = { .enable = omap2_dflt_clk_enable, .disable = omap2_dflt_clk_disable, @@ -327,6 +343,10 @@ int omap2_clk_enable(struct clk *clk) } } + /* If clockdomain supports hardware control, enable it */ + if (clk->clkdm) + clkdm_allow_idle(clk->clkdm); + return 0; oce_err3: diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index e10ff2b..450aabf 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -41,6 +41,7 @@ /* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */ #define DPLL_LOW_POWER_STOP 0x1 +#define DPLL_MN_BYPASS 0x4 #define DPLL_LOW_POWER_BYPASS 0x5 #define DPLL_LOCKED 0x7 @@ -64,6 +65,11 @@ void omap3_noncore_dpll_disable(struct clk *clk); int omap4_dpllmx_gatectrl_read(struct clk *clk); void omap4_dpllmx_allow_gatectrl(struct clk *clk); void omap4_dpllmx_deny_gatectrl(struct clk *clk); +int omap4460_mpu_dpll_set_rate(struct clk *clk, unsigned long rate); +long omap4460_mpu_dpll_round_rate(struct clk *clk, unsigned long rate); +unsigned long omap4460_mpu_dpll_recalc(struct clk *clk); +long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate); +unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk); #ifdef CONFIG_OMAP_RESET_CLOCKS void omap2_clk_disable_unused(struct clk *clk); @@ -132,6 +138,7 @@ extern u8 cpu_mask; extern const struct clkops clkops_omap2_dflt_wait; extern const struct clkops clkops_dummy; extern const struct clkops clkops_omap2_dflt; +extern const struct clkops clkops_omap4_dflt_wait; extern struct clk_functions omap2_clk_functions; extern struct clk *vclk, *sclk; @@ -141,7 +148,9 @@ extern const struct clksel_rate gpt_sys_rates[]; extern const struct clksel_rate gfx_l3_rates[]; extern const struct clksel_rate dsp_ick_rates[]; -#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ) +#ifdef CONFIG_CPU_FREQ + +#ifdef CONFIG_ARCH_OMAP2 extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); #else @@ -149,6 +158,16 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) #define omap2_clk_exit_cpufreq_table 0 #endif +#ifdef CONFIG_ARCH_OMAP3 +extern void omap3_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); +extern void omap3_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); +#else +#define omap3_clk_init_cpufreq_table 0 +#define omap3_clk_exit_cpufreq_table 0 +#endif + +#endif /* CONFIG_CPU_FREQ */ + extern const struct clkops clkops_omap2_iclk_dflt_wait; extern const struct clkops clkops_omap2_iclk_dflt; extern const struct clkops clkops_omap2_iclk_idle_only; diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c index 2926d02..f44d070 100644 --- a/arch/arm/mach-omap2/clock2420_data.c +++ b/arch/arm/mach-omap2/clock2420_data.c @@ -1820,29 +1820,29 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_242X), /* general l4 interface ck, multi-parent functional clk */ CLK(NULL, "gpt1_ick", &gpt1_ick, CK_242X), - CLK(NULL, "gpt1_fck", &gpt1_fck, CK_242X), + CLK("omap_timer.1", "fck", &gpt1_fck, CK_242X), CLK(NULL, "gpt2_ick", &gpt2_ick, CK_242X), - CLK(NULL, "gpt2_fck", &gpt2_fck, CK_242X), + CLK("omap_timer.2", "fck", &gpt2_fck, CK_242X), CLK(NULL, "gpt3_ick", &gpt3_ick, CK_242X), - CLK(NULL, "gpt3_fck", &gpt3_fck, CK_242X), + CLK("omap_timer.3", "fck", &gpt3_fck, CK_242X), CLK(NULL, "gpt4_ick", &gpt4_ick, CK_242X), - CLK(NULL, "gpt4_fck", &gpt4_fck, CK_242X), + CLK("omap_timer.4", "fck", &gpt4_fck, CK_242X), CLK(NULL, "gpt5_ick", &gpt5_ick, CK_242X), - CLK(NULL, "gpt5_fck", &gpt5_fck, CK_242X), + CLK("omap_timer.5", "fck", &gpt5_fck, CK_242X), CLK(NULL, "gpt6_ick", &gpt6_ick, CK_242X), - CLK(NULL, "gpt6_fck", &gpt6_fck, CK_242X), + CLK("omap_timer.6", "fck", &gpt6_fck, CK_242X), CLK(NULL, "gpt7_ick", &gpt7_ick, CK_242X), - CLK(NULL, "gpt7_fck", &gpt7_fck, CK_242X), + CLK("omap_timer.7", "fck", &gpt7_fck, CK_242X), CLK(NULL, "gpt8_ick", &gpt8_ick, CK_242X), - CLK(NULL, "gpt8_fck", &gpt8_fck, CK_242X), + CLK("omap_timer.8", "fck", &gpt8_fck, CK_242X), CLK(NULL, "gpt9_ick", &gpt9_ick, CK_242X), - CLK(NULL, "gpt9_fck", &gpt9_fck, CK_242X), + CLK("omap_timer.9", "fck", &gpt9_fck, CK_242X), CLK(NULL, "gpt10_ick", &gpt10_ick, CK_242X), - CLK(NULL, "gpt10_fck", &gpt10_fck, CK_242X), + CLK("omap_timer.10", "fck", &gpt10_fck, CK_242X), CLK(NULL, "gpt11_ick", &gpt11_ick, CK_242X), - CLK(NULL, "gpt11_fck", &gpt11_fck, CK_242X), + CLK("omap_timer.11", "fck", &gpt11_fck, CK_242X), CLK(NULL, "gpt12_ick", &gpt12_ick, CK_242X), - CLK(NULL, "gpt12_fck", &gpt12_fck, CK_242X), + CLK("omap_timer.12", "fck", &gpt12_fck, CK_242X), CLK("omap-mcbsp.1", "ick", &mcbsp1_ick, CK_242X), CLK("omap-mcbsp.1", "fck", &mcbsp1_fck, CK_242X), CLK("omap-mcbsp.2", "ick", &mcbsp2_ick, CK_242X), @@ -1898,6 +1898,54 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "pka_ick", &pka_ick, CK_242X), CLK(NULL, "usb_fck", &usb_fck, CK_242X), CLK("musb-hdrc", "fck", &osc_ck, CK_242X), + CLK("omap_timer.1", "fck", &gpt1_fck, CK_242X), + CLK("omap_timer.2", "fck", &gpt2_fck, CK_242X), + CLK("omap_timer.3", "fck", &gpt3_fck, CK_242X), + CLK("omap_timer.4", "fck", &gpt4_fck, CK_242X), + CLK("omap_timer.5", "fck", &gpt5_fck, CK_242X), + CLK("omap_timer.6", "fck", &gpt6_fck, CK_242X), + CLK("omap_timer.7", "fck", &gpt7_fck, CK_242X), + CLK("omap_timer.8", "fck", &gpt8_fck, CK_242X), + CLK("omap_timer.9", "fck", &gpt9_fck, CK_242X), + CLK("omap_timer.10", "fck", &gpt10_fck, CK_242X), + CLK("omap_timer.11", "fck", &gpt11_fck, CK_242X), + CLK("omap_timer.12", "fck", &gpt12_fck, CK_242X), + CLK("omap_timer.1", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.2", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.3", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.4", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.5", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.6", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.7", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.8", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.9", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.10", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.11", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.12", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.1", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.2", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.3", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.4", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.5", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.6", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.7", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.8", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.9", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.10", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.11", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.12", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.1", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.2", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.3", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.4", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.5", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.6", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.7", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.8", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.9", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.10", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.11", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.12", "alt_ck", &alt_ck, CK_243X), }; /* diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c index 0c79d39..cffd1c3 100644 --- a/arch/arm/mach-omap2/clock2430_data.c +++ b/arch/arm/mach-omap2/clock2430_data.c @@ -1910,29 +1910,29 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_243X), /* general l4 interface ck, multi-parent functional clk */ CLK(NULL, "gpt1_ick", &gpt1_ick, CK_243X), - CLK(NULL, "gpt1_fck", &gpt1_fck, CK_243X), + CLK("omap_timer.1", "fck", &gpt1_fck, CK_243X), CLK(NULL, "gpt2_ick", &gpt2_ick, CK_243X), - CLK(NULL, "gpt2_fck", &gpt2_fck, CK_243X), + CLK("omap_timer.2", "fck", &gpt2_fck, CK_243X), CLK(NULL, "gpt3_ick", &gpt3_ick, CK_243X), - CLK(NULL, "gpt3_fck", &gpt3_fck, CK_243X), + CLK("omap_timer.3", "fck", &gpt3_fck, CK_243X), CLK(NULL, "gpt4_ick", &gpt4_ick, CK_243X), - CLK(NULL, "gpt4_fck", &gpt4_fck, CK_243X), + CLK("omap_timer.4", "fck", &gpt4_fck, CK_243X), CLK(NULL, "gpt5_ick", &gpt5_ick, CK_243X), - CLK(NULL, "gpt5_fck", &gpt5_fck, CK_243X), + CLK("omap_timer.5", "fck", &gpt5_fck, CK_243X), CLK(NULL, "gpt6_ick", &gpt6_ick, CK_243X), - CLK(NULL, "gpt6_fck", &gpt6_fck, CK_243X), + CLK("omap_timer.6", "fck", &gpt6_fck, CK_243X), CLK(NULL, "gpt7_ick", &gpt7_ick, CK_243X), - CLK(NULL, "gpt7_fck", &gpt7_fck, CK_243X), + CLK("omap_timer.7", "fck", &gpt7_fck, CK_243X), CLK(NULL, "gpt8_ick", &gpt8_ick, CK_243X), - CLK(NULL, "gpt8_fck", &gpt8_fck, CK_243X), + CLK("omap_timer.8", "fck", &gpt8_fck, CK_243X), CLK(NULL, "gpt9_ick", &gpt9_ick, CK_243X), - CLK(NULL, "gpt9_fck", &gpt9_fck, CK_243X), + CLK("omap_timer.9", "fck", &gpt9_fck, CK_243X), CLK(NULL, "gpt10_ick", &gpt10_ick, CK_243X), - CLK(NULL, "gpt10_fck", &gpt10_fck, CK_243X), + CLK("omap_timer.10", "fck", &gpt10_fck, CK_243X), CLK(NULL, "gpt11_ick", &gpt11_ick, CK_243X), - CLK(NULL, "gpt11_fck", &gpt11_fck, CK_243X), + CLK("omap_timer.11", "fck", &gpt11_fck, CK_243X), CLK(NULL, "gpt12_ick", &gpt12_ick, CK_243X), - CLK(NULL, "gpt12_fck", &gpt12_fck, CK_243X), + CLK("omap_timer.12", "fck", &gpt12_fck, CK_243X), CLK("omap-mcbsp.1", "ick", &mcbsp1_ick, CK_243X), CLK("omap-mcbsp.1", "fck", &mcbsp1_fck, CK_243X), CLK("omap-mcbsp.2", "ick", &mcbsp2_ick, CK_243X), @@ -1998,6 +1998,42 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "mdm_intc_ick", &mdm_intc_ick, CK_243X), CLK("omap_hsmmc.0", "mmchsdb_fck", &mmchsdb1_fck, CK_243X), CLK("omap_hsmmc.1", "mmchsdb_fck", &mmchsdb2_fck, CK_243X), + CLK("omap_timer.1", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.2", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.3", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.4", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.5", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.6", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.7", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.8", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.9", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.10", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.11", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.12", "32k_ck", &func_32k_ck, CK_243X), + CLK("omap_timer.1", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.2", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.3", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.4", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.5", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.6", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.7", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.8", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.9", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.10", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.11", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.12", "sys_ck", &sys_ck, CK_243X), + CLK("omap_timer.1", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.2", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.3", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.4", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.5", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.6", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.7", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.8", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.9", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.10", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.11", "alt_ck", &alt_ck, CK_243X), + CLK("omap_timer.12", "alt_ck", &alt_ck, CK_243X), }; /* diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 1fc96b9..119e135 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -20,6 +20,8 @@ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/err.h> +#include <linux/cpufreq.h> #include <plat/clock.h> diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c index 75b119b..a7d698a 100644 --- a/arch/arm/mach-omap2/clock3xxx_data.c +++ b/arch/arm/mach-omap2/clock3xxx_data.c @@ -3280,12 +3280,12 @@ static struct omap_clk omap3xxx_clks[] = { CLK(NULL, "modem_fck", &modem_fck, CK_34XX | CK_36XX), CLK(NULL, "sad2d_ick", &sad2d_ick, CK_34XX | CK_36XX), CLK(NULL, "mad2d_ick", &mad2d_ick, CK_34XX | CK_36XX), - CLK(NULL, "gpt10_fck", &gpt10_fck, CK_3XXX), - CLK(NULL, "gpt11_fck", &gpt11_fck, CK_3XXX), + CLK("omap_timer.10", "fck", &gpt10_fck, CK_3XXX), + CLK("omap_timer.11", "fck", &gpt11_fck, CK_3XXX), CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), - CLK("usbhs-omap.0", "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), + CLK("usbhs_omap", "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), CLK("omap-mcbsp.1", "prcm_fck", &core_96m_fck, CK_3XXX), CLK("omap-mcbsp.5", "prcm_fck", &core_96m_fck, CK_3XXX), CLK(NULL, "core_96m_fck", &core_96m_fck, CK_3XXX), @@ -3321,7 +3321,7 @@ static struct omap_clk omap3xxx_clks[] = { CLK(NULL, "pka_ick", &pka_ick, CK_34XX | CK_36XX), CLK(NULL, "core_l4_ick", &core_l4_ick, CK_3XXX), CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), - CLK("usbhs-omap.0", "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), + CLK("usbhs_omap", "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), CLK("omap_hsmmc.2", "ick", &mmchs3_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), CLK(NULL, "icr_ick", &icr_ick, CK_34XX | CK_36XX), CLK("omap-aes", "ick", &aes2_ick, CK_34XX | CK_36XX), @@ -3367,22 +3367,22 @@ static struct omap_clk omap3xxx_clks[] = { CLK(NULL, "cam_ick", &cam_ick, CK_34XX | CK_36XX), CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_34XX | CK_36XX), CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), - CLK("usbhs-omap.0", "hs_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), + CLK("usbhs_omap", "hs_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), - CLK("usbhs-omap.0", "fs_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), + CLK("usbhs_omap", "fs_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), - CLK("usbhs-omap.0", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), - CLK("usbhs-omap.0", "utmi_p1_gfclk", &dummy_ck, CK_3XXX), - CLK("usbhs-omap.0", "utmi_p2_gfclk", &dummy_ck, CK_3XXX), - CLK("usbhs-omap.0", "xclk60mhsp1_ck", &dummy_ck, CK_3XXX), - CLK("usbhs-omap.0", "xclk60mhsp2_ck", &dummy_ck, CK_3XXX), - CLK("usbhs-omap.0", "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX), - CLK("usbhs-omap.0", "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX), - CLK("usbhs-omap.0", "usb_tll_hs_usb_ch0_clk", &dummy_ck, CK_3XXX), - CLK("usbhs-omap.0", "usb_tll_hs_usb_ch1_clk", &dummy_ck, CK_3XXX), - CLK("usbhs-omap.0", "init_60m_fclk", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX), + CLK("usbhs_omap", "utmi_p1_gfclk", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "utmi_p2_gfclk", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "xclk60mhsp1_ck", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "xclk60mhsp2_ck", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "usb_tll_hs_usb_ch0_clk", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "usb_tll_hs_usb_ch1_clk", &dummy_ck, CK_3XXX), + CLK("usbhs_omap", "init_60m_fclk", &dummy_ck, CK_3XXX), CLK(NULL, "usim_fck", &usim_fck, CK_3430ES2PLUS | CK_36XX), - CLK(NULL, "gpt1_fck", &gpt1_fck, CK_3XXX), + CLK("omap_timer.1", "fck", &gpt1_fck, CK_3XXX), CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_3XXX), CLK(NULL, "gpio1_dbck", &gpio1_dbck, CK_3XXX), CLK("omap_wdt", "fck", &wdt2_fck, CK_3XXX), @@ -3401,14 +3401,14 @@ static struct omap_clk omap3xxx_clks[] = { CLK(NULL, "per_48m_fck", &per_48m_fck, CK_3XXX), CLK(NULL, "uart3_fck", &uart3_fck, CK_3XXX), CLK(NULL, "uart4_fck", &uart4_fck, CK_36XX), - CLK(NULL, "gpt2_fck", &gpt2_fck, CK_3XXX), - CLK(NULL, "gpt3_fck", &gpt3_fck, CK_3XXX), - CLK(NULL, "gpt4_fck", &gpt4_fck, CK_3XXX), - CLK(NULL, "gpt5_fck", &gpt5_fck, CK_3XXX), - CLK(NULL, "gpt6_fck", &gpt6_fck, CK_3XXX), - CLK(NULL, "gpt7_fck", &gpt7_fck, CK_3XXX), - CLK(NULL, "gpt8_fck", &gpt8_fck, CK_3XXX), - CLK(NULL, "gpt9_fck", &gpt9_fck, CK_3XXX), + CLK("omap_timer.2", "fck", &gpt2_fck, CK_3XXX), + CLK("omap_timer.3", "fck", &gpt3_fck, CK_3XXX), + CLK("omap_timer.4", "fck", &gpt4_fck, CK_3XXX), + CLK("omap_timer.5", "fck", &gpt5_fck, CK_3XXX), + CLK("omap_timer.6", "fck", &gpt6_fck, CK_3XXX), + CLK("omap_timer.7", "fck", &gpt7_fck, CK_3XXX), + CLK("omap_timer.8", "fck", &gpt8_fck, CK_3XXX), + CLK("omap_timer.9", "fck", &gpt9_fck, CK_3XXX), CLK(NULL, "per_32k_alwon_fck", &per_32k_alwon_fck, CK_3XXX), CLK(NULL, "gpio6_dbck", &gpio6_dbck, CK_3XXX), CLK(NULL, "gpio5_dbck", &gpio5_dbck, CK_3XXX), @@ -3449,7 +3449,7 @@ static struct omap_clk omap3xxx_clks[] = { CLK(NULL, "sr2_fck", &sr2_fck, CK_34XX | CK_36XX), CLK(NULL, "sr_l4_ick", &sr_l4_ick, CK_34XX | CK_36XX), CLK(NULL, "secure_32k_fck", &secure_32k_fck, CK_3XXX), - CLK(NULL, "gpt12_fck", &gpt12_fck, CK_3XXX), + CLK("omap_timer.12", "fck", &gpt12_fck, CK_3XXX), CLK(NULL, "wdt1_fck", &wdt1_fck, CK_3XXX), CLK(NULL, "ipss_ick", &ipss_ick, CK_AM35XX), CLK(NULL, "rmii_ck", &rmii_ck, CK_AM35XX), @@ -3462,6 +3462,30 @@ static struct omap_clk omap3xxx_clks[] = { CLK("musb-am35x", "fck", &hsotgusb_fck_am35xx, CK_AM35XX), CLK(NULL, "hecc_ck", &hecc_ck, CK_AM35XX), CLK(NULL, "uart4_ick", &uart4_ick_am35xx, CK_AM35XX), + CLK("omap_timer.1", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.2", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.3", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.4", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.5", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.6", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.7", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.8", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.9", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.10", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.11", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.12", "32k_ck", &omap_32k_fck, CK_3XXX), + CLK("omap_timer.1", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.2", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.3", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.4", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.5", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.6", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.7", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.8", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.9", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.10", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.11", "sys_ck", &sys_ck, CK_3XXX), + CLK("omap_timer.12", "sys_ck", &sys_ck, CK_3XXX), }; diff --git a/arch/arm/mach-omap2/clock44xx.h b/arch/arm/mach-omap2/clock44xx.h index 6be1095..bdc5f0d 100644 --- a/arch/arm/mach-omap2/clock44xx.h +++ b/arch/arm/mach-omap2/clock44xx.h @@ -14,7 +14,9 @@ */ #define OMAP4430_MAX_DPLL_MULT 2047 #define OMAP4430_MAX_DPLL_DIV 128 +#define OMAP4430_REGM4XEN_MULT 4 int omap4xxx_clk_init(void); +int omap4_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate); #endif diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 8c96567..6089ff0 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -1,7 +1,7 @@ /* - * OMAP4 Clock data + * OMAP44xx Clock data * - * Copyright (C) 2009-2010 Texas Instruments, Inc. + * Copyright (C) 2009-2011 Texas Instruments Incorporated * Copyright (C) 2009-2010 Nokia Corporation * * Paul Walmsley (paul@pwsan.com) @@ -42,6 +42,10 @@ #define OMAP4430_MODULEMODE_HWCTRL 0 #define OMAP4430_MODULEMODE_SWCTRL 1 +static int omap4_virt_l3_set_rate(struct clk *clk, unsigned long rate); +static long omap4_virt_l3_round_rate(struct clk *clk, unsigned long rate); +static unsigned long omap4_virt_l3_recalc(struct clk *clk); + /* Root clocks */ static struct clk extalt_clkin_ck = { @@ -53,7 +57,7 @@ static struct clk extalt_clkin_ck = { static struct clk pad_clks_ck = { .name = "pad_clks_ck", .rate = 12000000, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_CLKSEL_ABE, .enable_bit = OMAP4430_PAD_CLKS_GATE_SHIFT, }; @@ -73,7 +77,7 @@ static struct clk secure_32k_clk_src_ck = { static struct clk slimbus_clk = { .name = "slimbus_clk", .rate = 12000000, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_CLKSEL_ABE, .enable_bit = OMAP4430_SLIMBUS_CLK_GATE_SHIFT, }; @@ -127,42 +131,42 @@ static struct clk virt_38400000_ck = { }; static const struct clksel_rate div_1_0_rates[] = { - { .div = 1, .val = 0, .flags = RATE_IN_4430 }, + { .div = 1, .val = 0, .flags = RATE_IN_44XX }, { .div = 0 }, }; static const struct clksel_rate div_1_1_rates[] = { - { .div = 1, .val = 1, .flags = RATE_IN_4430 }, + { .div = 1, .val = 1, .flags = RATE_IN_44XX }, { .div = 0 }, }; static const struct clksel_rate div_1_2_rates[] = { - { .div = 1, .val = 2, .flags = RATE_IN_4430 }, + { .div = 1, .val = 2, .flags = RATE_IN_44XX }, { .div = 0 }, }; static const struct clksel_rate div_1_3_rates[] = { - { .div = 1, .val = 3, .flags = RATE_IN_4430 }, + { .div = 1, .val = 3, .flags = RATE_IN_44XX }, { .div = 0 }, }; static const struct clksel_rate div_1_4_rates[] = { - { .div = 1, .val = 4, .flags = RATE_IN_4430 }, + { .div = 1, .val = 4, .flags = RATE_IN_44XX }, { .div = 0 }, }; static const struct clksel_rate div_1_5_rates[] = { - { .div = 1, .val = 5, .flags = RATE_IN_4430 }, + { .div = 1, .val = 5, .flags = RATE_IN_44XX }, { .div = 0 }, }; static const struct clksel_rate div_1_6_rates[] = { - { .div = 1, .val = 6, .flags = RATE_IN_4430 }, + { .div = 1, .val = 6, .flags = RATE_IN_44XX }, { .div = 0 }, }; static const struct clksel_rate div_1_7_rates[] = { - { .div = 1, .val = 7, .flags = RATE_IN_4430 }, + { .div = 1, .val = 7, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -194,12 +198,6 @@ static struct clk tie_low_clock_ck = { .ops = &clkops_null, }; -static struct clk utmi_phy_clkout_ck = { - .name = "utmi_phy_clkout_ck", - .rate = 60000000, - .ops = &clkops_null, -}; - static struct clk xclk60mhsp1_ck = { .name = "xclk60mhsp1_ck", .rate = 60000000, @@ -270,8 +268,8 @@ static struct clk dpll_abe_ck = { .dpll_data = &dpll_abe_dd, .init = &omap2_init_dpll_parent, .ops = &clkops_omap3_noncore_dpll_ops, - .recalc = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, + .recalc = &omap4_dpll_regm4xen_recalc, + .round_rate = &omap4_dpll_regm4xen_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, }; @@ -285,37 +283,37 @@ static struct clk dpll_abe_x2_ck = { }; static const struct clksel_rate div31_1to31_rates[] = { - { .div = 1, .val = 1, .flags = RATE_IN_4430 }, - { .div = 2, .val = 2, .flags = RATE_IN_4430 }, - { .div = 3, .val = 3, .flags = RATE_IN_4430 }, - { .div = 4, .val = 4, .flags = RATE_IN_4430 }, - { .div = 5, .val = 5, .flags = RATE_IN_4430 }, - { .div = 6, .val = 6, .flags = RATE_IN_4430 }, - { .div = 7, .val = 7, .flags = RATE_IN_4430 }, - { .div = 8, .val = 8, .flags = RATE_IN_4430 }, - { .div = 9, .val = 9, .flags = RATE_IN_4430 }, - { .div = 10, .val = 10, .flags = RATE_IN_4430 }, - { .div = 11, .val = 11, .flags = RATE_IN_4430 }, - { .div = 12, .val = 12, .flags = RATE_IN_4430 }, - { .div = 13, .val = 13, .flags = RATE_IN_4430 }, - { .div = 14, .val = 14, .flags = RATE_IN_4430 }, - { .div = 15, .val = 15, .flags = RATE_IN_4430 }, - { .div = 16, .val = 16, .flags = RATE_IN_4430 }, - { .div = 17, .val = 17, .flags = RATE_IN_4430 }, - { .div = 18, .val = 18, .flags = RATE_IN_4430 }, - { .div = 19, .val = 19, .flags = RATE_IN_4430 }, - { .div = 20, .val = 20, .flags = RATE_IN_4430 }, - { .div = 21, .val = 21, .flags = RATE_IN_4430 }, - { .div = 22, .val = 22, .flags = RATE_IN_4430 }, - { .div = 23, .val = 23, .flags = RATE_IN_4430 }, - { .div = 24, .val = 24, .flags = RATE_IN_4430 }, - { .div = 25, .val = 25, .flags = RATE_IN_4430 }, - { .div = 26, .val = 26, .flags = RATE_IN_4430 }, - { .div = 27, .val = 27, .flags = RATE_IN_4430 }, - { .div = 28, .val = 28, .flags = RATE_IN_4430 }, - { .div = 29, .val = 29, .flags = RATE_IN_4430 }, - { .div = 30, .val = 30, .flags = RATE_IN_4430 }, - { .div = 31, .val = 31, .flags = RATE_IN_4430 }, + { .div = 1, .val = 1, .flags = RATE_IN_44XX }, + { .div = 2, .val = 2, .flags = RATE_IN_44XX }, + { .div = 3, .val = 3, .flags = RATE_IN_44XX }, + { .div = 4, .val = 4, .flags = RATE_IN_44XX }, + { .div = 5, .val = 5, .flags = RATE_IN_44XX }, + { .div = 6, .val = 6, .flags = RATE_IN_44XX }, + { .div = 7, .val = 7, .flags = RATE_IN_44XX }, + { .div = 8, .val = 8, .flags = RATE_IN_44XX }, + { .div = 9, .val = 9, .flags = RATE_IN_44XX }, + { .div = 10, .val = 10, .flags = RATE_IN_44XX }, + { .div = 11, .val = 11, .flags = RATE_IN_44XX }, + { .div = 12, .val = 12, .flags = RATE_IN_44XX }, + { .div = 13, .val = 13, .flags = RATE_IN_44XX }, + { .div = 14, .val = 14, .flags = RATE_IN_44XX }, + { .div = 15, .val = 15, .flags = RATE_IN_44XX }, + { .div = 16, .val = 16, .flags = RATE_IN_44XX }, + { .div = 17, .val = 17, .flags = RATE_IN_44XX }, + { .div = 18, .val = 18, .flags = RATE_IN_44XX }, + { .div = 19, .val = 19, .flags = RATE_IN_44XX }, + { .div = 20, .val = 20, .flags = RATE_IN_44XX }, + { .div = 21, .val = 21, .flags = RATE_IN_44XX }, + { .div = 22, .val = 22, .flags = RATE_IN_44XX }, + { .div = 23, .val = 23, .flags = RATE_IN_44XX }, + { .div = 24, .val = 24, .flags = RATE_IN_44XX }, + { .div = 25, .val = 25, .flags = RATE_IN_44XX }, + { .div = 26, .val = 26, .flags = RATE_IN_44XX }, + { .div = 27, .val = 27, .flags = RATE_IN_44XX }, + { .div = 28, .val = 28, .flags = RATE_IN_44XX }, + { .div = 29, .val = 29, .flags = RATE_IN_44XX }, + { .div = 30, .val = 30, .flags = RATE_IN_44XX }, + { .div = 31, .val = 31, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -345,9 +343,9 @@ static struct clk abe_24m_fclk = { }; static const struct clksel_rate div3_1to4_rates[] = { - { .div = 1, .val = 0, .flags = RATE_IN_4430 }, - { .div = 2, .val = 1, .flags = RATE_IN_4430 }, - { .div = 4, .val = 2, .flags = RATE_IN_4430 }, + { .div = 1, .val = 0, .flags = RATE_IN_44XX }, + { .div = 2, .val = 1, .flags = RATE_IN_44XX }, + { .div = 4, .val = 2, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -369,8 +367,8 @@ static struct clk abe_clk = { }; static const struct clksel_rate div2_1to2_rates[] = { - { .div = 1, .val = 0, .flags = RATE_IN_4430 }, - { .div = 2, .val = 1, .flags = RATE_IN_4430 }, + { .div = 1, .val = 0, .flags = RATE_IN_44XX }, + { .div = 2, .val = 1, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -501,7 +499,7 @@ static struct clk dpll_core_m2_ck = { .ops = &clkops_omap4_dpllmx_ops, .recalc = &omap2_clksel_recalc, .round_rate = &omap2_clksel_round_rate, - .set_rate = &omap2_clksel_set_rate, + .set_rate = &omap4_core_dpll_m2_set_rate, }; static struct clk ddrphy_ck = { @@ -524,6 +522,15 @@ static struct clk dpll_core_m5x2_ck = { .set_rate = &omap2_clksel_set_rate, }; +static struct clk virt_l3_ck = { + .name = "virt_l3_ck", + .parent = &dpll_core_m5x2_ck, + .ops = &clkops_null, + .set_rate = &omap4_virt_l3_set_rate, + .recalc = &omap4_virt_l3_recalc, + .round_rate = &omap4_virt_l3_round_rate, +}; + static const struct clksel div_core_div[] = { { .parent = &dpll_core_m5x2_ck, .rates = div2_1to2_rates }, { .parent = NULL }, @@ -542,10 +549,10 @@ static struct clk div_core_ck = { }; static const struct clksel_rate div4_1to8_rates[] = { - { .div = 1, .val = 0, .flags = RATE_IN_4430 }, - { .div = 2, .val = 1, .flags = RATE_IN_4430 }, - { .div = 4, .val = 2, .flags = RATE_IN_4430 }, - { .div = 8, .val = 3, .flags = RATE_IN_4430 }, + { .div = 1, .val = 0, .flags = RATE_IN_44XX }, + { .div = 2, .val = 1, .flags = RATE_IN_44XX }, + { .div = 4, .val = 2, .flags = RATE_IN_44XX }, + { .div = 8, .val = 3, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -621,7 +628,7 @@ static struct clk dpll_core_m3x2_ck = { .clksel = dpll_core_m6x2_div, .clksel_reg = OMAP4430_CM_DIV_M3_DPLL_CORE, .clksel_mask = OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_DIV_M3_DPLL_CORE, .enable_bit = OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, .recalc = &omap2_clksel_recalc, @@ -774,6 +781,15 @@ static struct clk dpll_mpu_m2_ck = { .set_rate = &omap2_clksel_set_rate, }; +static struct clk virt_dpll_mpu_ck = { + .name = "virt_dpll_mpu_ck", + .parent = &dpll_mpu_ck, + .ops = &clkops_null, + .recalc = &omap4460_mpu_dpll_recalc, + .round_rate = &omap4460_mpu_dpll_round_rate, + .set_rate = &omap4460_mpu_dpll_set_rate, +}; + static struct clk per_hs_clk_div_ck = { .name = "per_hs_clk_div_ck", .parent = &dpll_abe_m3x2_ck, @@ -879,7 +895,7 @@ static struct clk dpll_per_m3x2_ck = { .clksel = dpll_per_m2x2_div, .clksel_reg = OMAP4430_CM_DIV_M3_DPLL_PER, .clksel_mask = OMAP4430_DPLL_CLKOUTHIF_DIV_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_DIV_M3_DPLL_PER, .enable_bit = OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, .recalc = &omap2_clksel_recalc, @@ -1007,7 +1023,8 @@ static struct dpll_data dpll_usb_dd = { .flags = DPLL_J_TYPE, .clk_ref = &sys_clkin_ck, .control_reg = OMAP4430_CM_CLKMODE_DPLL_USB, - .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED), + .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED) + | (1 << DPLL_LOW_POWER_STOP), .autoidle_reg = OMAP4430_CM_AUTOIDLE_DPLL_USB, .idlest_reg = OMAP4430_CM_IDLEST_DPLL_USB, .mult_mask = OMAP4430_DPLL_MULT_MASK, @@ -1030,6 +1047,7 @@ static struct clk dpll_usb_ck = { .recalc = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, + .clkdm_name = "l3_init_clkdm", }; static struct clk dpll_usb_clkdcoldo_ck = { @@ -1040,6 +1058,13 @@ static struct clk dpll_usb_clkdcoldo_ck = { .recalc = &followparent_recalc, }; +static struct clk utmi_phy_clkout_ck = { + .name = "utmi_phy_clkout_ck", + .ops = &clkops_null, + .parent = &dpll_usb_clkdcoldo_ck, + .recalc = &followparent_recalc, +}; + static const struct clksel dpll_usb_m2_div[] = { { .parent = &dpll_usb_ck, .rates = div31_1to31_rates }, { .parent = NULL }, @@ -1099,8 +1124,8 @@ static struct clk func_24mc_fclk = { }; static const struct clksel_rate div2_4to8_rates[] = { - { .div = 4, .val = 0, .flags = RATE_IN_4430 }, - { .div = 8, .val = 1, .flags = RATE_IN_4430 }, + { .div = 4, .val = 0, .flags = RATE_IN_44XX }, + { .div = 8, .val = 1, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -1130,8 +1155,8 @@ static struct clk func_48mc_fclk = { }; static const struct clksel_rate div2_2to4_rates[] = { - { .div = 2, .val = 0, .flags = RATE_IN_4430 }, - { .div = 4, .val = 1, .flags = RATE_IN_4430 }, + { .div = 2, .val = 0, .flags = RATE_IN_44XX }, + { .div = 4, .val = 1, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -1183,8 +1208,8 @@ static struct clk hsmmc6_fclk = { }; static const struct clksel_rate div2_1to8_rates[] = { - { .div = 1, .val = 0, .flags = RATE_IN_4430 }, - { .div = 8, .val = 1, .flags = RATE_IN_4430 }, + { .div = 1, .val = 0, .flags = RATE_IN_44XX }, + { .div = 8, .val = 1, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -1264,6 +1289,28 @@ static struct clk l4_wkup_clk_mux_ck = { .recalc = &omap2_clksel_recalc, }; +static const struct clksel_rate div3_8to32_rates[] = { + { .div = 8, .val = 0, .flags = RATE_IN_44XX }, + { .div = 16, .val = 1, .flags = RATE_IN_44XX }, + { .div = 32, .val = 2, .flags = RATE_IN_44XX }, + { .div = 0 }, +}; + +static const struct clksel div_ts_ck_div[] = { + { .parent = &l4_wkup_clk_mux_ck, .rates = div3_8to32_rates }, + { .parent = NULL }, +}; + +static struct clk div_ts_ck = { + .name = "div_ts_ck", + .parent = &l4_wkup_clk_mux_ck, + .clksel = div_ts_ck_div, + .clksel_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, + .clksel_mask = OMAP4430_CLKSEL_24_25_MASK, + .ops = &clkops_null, + .recalc = &omap2_clksel_recalc, +}; + static const struct clksel per_abe_nc_fclk_div[] = { { .parent = &dpll_abe_m2_ck, .rates = div2_1to2_rates }, { .parent = NULL }, @@ -1358,7 +1405,7 @@ static struct clk syc_clk_div_ck = { static struct clk aes1_fck = { .name = "aes1_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4SEC_AES1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_secure_clkdm", @@ -1368,7 +1415,7 @@ static struct clk aes1_fck = { static struct clk aes2_fck = { .name = "aes2_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4SEC_AES2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_secure_clkdm", @@ -1378,7 +1425,7 @@ static struct clk aes2_fck = { static struct clk aess_fck = { .name = "aess_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM1_ABE_AESS_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "abe_clkdm", @@ -1388,7 +1435,7 @@ static struct clk aess_fck = { static struct clk bandgap_fclk = { .name = "bandgap_fclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT, .clkdm_name = "l4_wkup_clkdm", @@ -1396,9 +1443,19 @@ static struct clk bandgap_fclk = { .recalc = &followparent_recalc, }; +static struct clk bandgap_ts_fclk = { + .name = "bandgap_ts_fclk", + .ops = &clkops_omap2_dflt, + .enable_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, + .enable_bit = OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT, + .clkdm_name = "l4_wkup_clkdm", + .parent = &div_ts_ck, + .recalc = &followparent_recalc, +}; + static struct clk des3des_fck = { .name = "des3des_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4SEC_DES3DES_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_secure_clkdm", @@ -1439,7 +1496,7 @@ static struct clk dmic_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_DMIC_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_SOURCE_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_DMIC_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -1448,7 +1505,7 @@ static struct clk dmic_fck = { static struct clk dsp_fck = { .name = "dsp_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_TESLA_TESLA_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "tesla_clkdm", @@ -1458,17 +1515,20 @@ static struct clk dsp_fck = { static struct clk dss_sys_clk = { .name = "dss_sys_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT, .clkdm_name = "l3_dss_clkdm", +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = ENABLE_ON_INIT, +#endif .parent = &syc_clk_div_ck, .recalc = &followparent_recalc, }; static struct clk dss_tv_clk = { .name = "dss_tv_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_TV_CLK_SHIFT, .clkdm_name = "l3_dss_clkdm", @@ -1478,7 +1538,7 @@ static struct clk dss_tv_clk = { static struct clk dss_dss_clk = { .name = "dss_dss_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_DSSCLK_SHIFT, .clkdm_name = "l3_dss_clkdm", @@ -1488,7 +1548,7 @@ static struct clk dss_dss_clk = { static struct clk dss_48mhz_clk = { .name = "dss_48mhz_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT, .clkdm_name = "l3_dss_clkdm", @@ -1498,17 +1558,20 @@ static struct clk dss_48mhz_clk = { static struct clk dss_fck = { .name = "dss_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l3_dss_clkdm", +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = ENABLE_ON_INIT, +#endif .parent = &l3_div_ck, .recalc = &followparent_recalc, }; static struct clk efuse_ctrl_cust_fck = { .name = "efuse_ctrl_cust_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_cefuse_clkdm", @@ -1518,10 +1581,9 @@ static struct clk efuse_ctrl_cust_fck = { static struct clk emif1_fck = { .name = "emif1_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, - .flags = ENABLE_ON_INIT, .clkdm_name = "l3_emif_clkdm", .parent = &ddrphy_ck, .recalc = &followparent_recalc, @@ -1529,10 +1591,9 @@ static struct clk emif1_fck = { static struct clk emif2_fck = { .name = "emif2_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, - .flags = ENABLE_ON_INIT, .clkdm_name = "l3_emif_clkdm", .parent = &ddrphy_ck, .recalc = &followparent_recalc, @@ -1550,7 +1611,7 @@ static struct clk fdif_fck = { .clksel = fdif_fclk_div, .clksel_reg = OMAP4430_CM_CAM_FDIF_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_FCLK_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .round_rate = &omap2_clksel_round_rate, .set_rate = &omap2_clksel_set_rate, @@ -1561,7 +1622,7 @@ static struct clk fdif_fck = { static struct clk fpka_fck = { .name = "fpka_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_secure_clkdm", @@ -1571,7 +1632,7 @@ static struct clk fpka_fck = { static struct clk gpio1_dbclk = { .name = "gpio1_dbclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_WKUP_GPIO1_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT, .clkdm_name = "l4_wkup_clkdm", @@ -1581,7 +1642,7 @@ static struct clk gpio1_dbclk = { static struct clk gpio1_ick = { .name = "gpio1_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_WKUP_GPIO1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l4_wkup_clkdm", @@ -1591,7 +1652,7 @@ static struct clk gpio1_ick = { static struct clk gpio2_dbclk = { .name = "gpio2_dbclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO2_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT, .clkdm_name = "l4_per_clkdm", @@ -1601,7 +1662,7 @@ static struct clk gpio2_dbclk = { static struct clk gpio2_ick = { .name = "gpio2_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1611,7 +1672,7 @@ static struct clk gpio2_ick = { static struct clk gpio3_dbclk = { .name = "gpio3_dbclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO3_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT, .clkdm_name = "l4_per_clkdm", @@ -1621,7 +1682,7 @@ static struct clk gpio3_dbclk = { static struct clk gpio3_ick = { .name = "gpio3_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1631,7 +1692,7 @@ static struct clk gpio3_ick = { static struct clk gpio4_dbclk = { .name = "gpio4_dbclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO4_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT, .clkdm_name = "l4_per_clkdm", @@ -1641,7 +1702,7 @@ static struct clk gpio4_dbclk = { static struct clk gpio4_ick = { .name = "gpio4_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO4_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1651,7 +1712,7 @@ static struct clk gpio4_ick = { static struct clk gpio5_dbclk = { .name = "gpio5_dbclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO5_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT, .clkdm_name = "l4_per_clkdm", @@ -1661,7 +1722,7 @@ static struct clk gpio5_dbclk = { static struct clk gpio5_ick = { .name = "gpio5_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO5_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1671,7 +1732,7 @@ static struct clk gpio5_ick = { static struct clk gpio6_dbclk = { .name = "gpio6_dbclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO6_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_DBCLK_SHIFT, .clkdm_name = "l4_per_clkdm", @@ -1681,7 +1742,7 @@ static struct clk gpio6_dbclk = { static struct clk gpio6_ick = { .name = "gpio6_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_GPIO6_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1691,10 +1752,11 @@ static struct clk gpio6_ick = { static struct clk gpmc_ick = { .name = "gpmc_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3_2_GPMC_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l3_2_clkdm", + .flags = ENABLE_ON_INIT, .parent = &l3_div_ck, .recalc = &followparent_recalc, }; @@ -1713,7 +1775,7 @@ static struct clk gpu_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_GFX_GFX_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_SGX_FCLK_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_GFX_GFX_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -1722,7 +1784,7 @@ static struct clk gpu_fck = { static struct clk hdq1w_fck = { .name = "hdq1w_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_HDQ1W_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1742,7 +1804,7 @@ static struct clk hsi_fck = { .clksel = hsi_fclk_div, .clksel_reg = OMAP4430_CM_L3INIT_HSI_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_24_25_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .round_rate = &omap2_clksel_round_rate, .set_rate = &omap2_clksel_set_rate, @@ -1753,7 +1815,7 @@ static struct clk hsi_fck = { static struct clk i2c1_fck = { .name = "i2c1_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_I2C1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1763,7 +1825,7 @@ static struct clk i2c1_fck = { static struct clk i2c2_fck = { .name = "i2c2_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_I2C2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1773,7 +1835,7 @@ static struct clk i2c2_fck = { static struct clk i2c3_fck = { .name = "i2c3_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_I2C3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1783,7 +1845,7 @@ static struct clk i2c3_fck = { static struct clk i2c4_fck = { .name = "i2c4_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_I2C4_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -1793,7 +1855,7 @@ static struct clk i2c4_fck = { static struct clk ipu_fck = { .name = "ipu_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "ducati_clkdm", @@ -1803,7 +1865,7 @@ static struct clk ipu_fck = { static struct clk iss_ctrlclk = { .name = "iss_ctrlclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_CAM_ISS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT, .clkdm_name = "iss_clkdm", @@ -1813,7 +1875,7 @@ static struct clk iss_ctrlclk = { static struct clk iss_fck = { .name = "iss_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_CAM_ISS_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "iss_clkdm", @@ -1823,7 +1885,7 @@ static struct clk iss_fck = { static struct clk iva_fck = { .name = "iva_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_IVAHD_IVAHD_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "ivahd_clkdm", @@ -1833,7 +1895,7 @@ static struct clk iva_fck = { static struct clk kbd_fck = { .name = "kbd_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_wkup_clkdm", @@ -1843,7 +1905,7 @@ static struct clk kbd_fck = { static struct clk l3_instr_ick = { .name = "l3_instr_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l3_instr_clkdm", @@ -1854,7 +1916,7 @@ static struct clk l3_instr_ick = { static struct clk l3_main_3_ick = { .name = "l3_main_3_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l3_instr_clkdm", @@ -1889,7 +1951,7 @@ static struct clk mcasp_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_MCASP_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_SOURCE_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_MCASP_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -1922,7 +1984,7 @@ static struct clk mcbsp1_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_SOURCE_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -1955,7 +2017,7 @@ static struct clk mcbsp2_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_SOURCE_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -1988,7 +2050,7 @@ static struct clk mcbsp3_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_SOURCE_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2020,7 +2082,7 @@ static struct clk mcbsp4_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_SOURCE_24_24_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2029,7 +2091,7 @@ static struct clk mcbsp4_fck = { static struct clk mcpdm_fck = { .name = "mcpdm_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM1_ABE_PDM_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "abe_clkdm", @@ -2039,7 +2101,7 @@ static struct clk mcpdm_fck = { static struct clk mcspi1_fck = { .name = "mcspi1_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_MCSPI1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2049,7 +2111,7 @@ static struct clk mcspi1_fck = { static struct clk mcspi2_fck = { .name = "mcspi2_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_MCSPI2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2059,7 +2121,7 @@ static struct clk mcspi2_fck = { static struct clk mcspi3_fck = { .name = "mcspi3_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_MCSPI3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2069,7 +2131,7 @@ static struct clk mcspi3_fck = { static struct clk mcspi4_fck = { .name = "mcspi4_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_MCSPI4_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2085,7 +2147,7 @@ static struct clk mmc1_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L3INIT_MMC1_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L3INIT_MMC1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2100,7 +2162,7 @@ static struct clk mmc2_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L3INIT_MMC2_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L3INIT_MMC2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2109,7 +2171,7 @@ static struct clk mmc2_fck = { static struct clk mmc3_fck = { .name = "mmc3_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_MMCSD3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2119,7 +2181,7 @@ static struct clk mmc3_fck = { static struct clk mmc4_fck = { .name = "mmc4_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_MMCSD4_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2129,7 +2191,7 @@ static struct clk mmc4_fck = { static struct clk mmc5_fck = { .name = "mmc5_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_MMCSD5_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2139,7 +2201,7 @@ static struct clk mmc5_fck = { static struct clk ocp2scp_usb_phy_phy_48m = { .name = "ocp2scp_usb_phy_phy_48m", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2149,7 +2211,7 @@ static struct clk ocp2scp_usb_phy_phy_48m = { static struct clk ocp2scp_usb_phy_ick = { .name = "ocp2scp_usb_phy_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l3_init_clkdm", @@ -2159,7 +2221,7 @@ static struct clk ocp2scp_usb_phy_ick = { static struct clk ocp_wp_noc_ick = { .name = "ocp_wp_noc_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l3_instr_clkdm", @@ -2170,7 +2232,7 @@ static struct clk ocp_wp_noc_ick = { static struct clk rng_ick = { .name = "rng_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4SEC_RNG_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l4_secure_clkdm", @@ -2180,7 +2242,7 @@ static struct clk rng_ick = { static struct clk sha2md5_fck = { .name = "sha2md5_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_secure_clkdm", @@ -2190,7 +2252,7 @@ static struct clk sha2md5_fck = { static struct clk sl2if_ick = { .name = "sl2if_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_IVAHD_SL2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "ivahd_clkdm", @@ -2200,7 +2262,7 @@ static struct clk sl2if_ick = { static struct clk slimbus1_fclk_1 = { .name = "slimbus1_fclk_1", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_FCLK1_SHIFT, .clkdm_name = "abe_clkdm", @@ -2210,7 +2272,7 @@ static struct clk slimbus1_fclk_1 = { static struct clk slimbus1_fclk_0 = { .name = "slimbus1_fclk_0", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_FCLK0_SHIFT, .clkdm_name = "abe_clkdm", @@ -2220,7 +2282,7 @@ static struct clk slimbus1_fclk_0 = { static struct clk slimbus1_fclk_2 = { .name = "slimbus1_fclk_2", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_FCLK2_SHIFT, .clkdm_name = "abe_clkdm", @@ -2230,7 +2292,7 @@ static struct clk slimbus1_fclk_2 = { static struct clk slimbus1_slimbus_clk = { .name = "slimbus1_slimbus_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT, .clkdm_name = "abe_clkdm", @@ -2240,7 +2302,7 @@ static struct clk slimbus1_slimbus_clk = { static struct clk slimbus1_fck = { .name = "slimbus1_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "abe_clkdm", @@ -2250,7 +2312,7 @@ static struct clk slimbus1_fck = { static struct clk slimbus2_fclk_1 = { .name = "slimbus2_fclk_1", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT, .clkdm_name = "l4_per_clkdm", @@ -2260,7 +2322,7 @@ static struct clk slimbus2_fclk_1 = { static struct clk slimbus2_fclk_0 = { .name = "slimbus2_fclk_0", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT, .clkdm_name = "l4_per_clkdm", @@ -2270,7 +2332,7 @@ static struct clk slimbus2_fclk_0 = { static struct clk slimbus2_slimbus_clk = { .name = "slimbus2_slimbus_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT, .clkdm_name = "l4_per_clkdm", @@ -2280,7 +2342,7 @@ static struct clk slimbus2_slimbus_clk = { static struct clk slimbus2_fck = { .name = "slimbus2_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2290,7 +2352,7 @@ static struct clk slimbus2_fck = { static struct clk smartreflex_core_fck = { .name = "smartreflex_core_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_ALWON_SR_CORE_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_ao_clkdm", @@ -2300,7 +2362,7 @@ static struct clk smartreflex_core_fck = { static struct clk smartreflex_iva_fck = { .name = "smartreflex_iva_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_ALWON_SR_IVA_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_ao_clkdm", @@ -2310,7 +2372,7 @@ static struct clk smartreflex_iva_fck = { static struct clk smartreflex_mpu_fck = { .name = "smartreflex_mpu_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_ALWON_SR_MPU_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_ao_clkdm", @@ -2326,7 +2388,7 @@ static struct clk timer1_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_WKUP_TIMER1_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_WKUP_TIMER1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2341,7 +2403,7 @@ static struct clk timer10_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2356,7 +2418,7 @@ static struct clk timer11_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2371,7 +2433,7 @@ static struct clk timer2_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2386,7 +2448,7 @@ static struct clk timer3_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2401,7 +2463,7 @@ static struct clk timer4_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2422,7 +2484,7 @@ static struct clk timer5_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2437,7 +2499,7 @@ static struct clk timer6_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2452,7 +2514,7 @@ static struct clk timer7_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2467,7 +2529,7 @@ static struct clk timer8_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2482,7 +2544,7 @@ static struct clk timer9_fck = { .init = &omap2_init_clksel_parent, .clksel_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_MASK, - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, @@ -2491,7 +2553,7 @@ static struct clk timer9_fck = { static struct clk uart1_fck = { .name = "uart1_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_UART1_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2501,7 +2563,7 @@ static struct clk uart1_fck = { static struct clk uart2_fck = { .name = "uart2_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_UART2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2511,7 +2573,7 @@ static struct clk uart2_fck = { static struct clk uart3_fck = { .name = "uart3_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_UART3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2521,7 +2583,7 @@ static struct clk uart3_fck = { static struct clk uart4_fck = { .name = "uart4_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L4PER_UART4_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_per_clkdm", @@ -2531,7 +2593,7 @@ static struct clk uart4_fck = { static struct clk usb_host_fs_fck = { .name = "usb_host_fs_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l3_init_clkdm", @@ -2558,7 +2620,7 @@ static struct clk utmi_p1_gfclk = { static struct clk usb_host_hs_utmi_p1_clk = { .name = "usb_host_hs_utmi_p1_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2585,7 +2647,7 @@ static struct clk utmi_p2_gfclk = { static struct clk usb_host_hs_utmi_p2_clk = { .name = "usb_host_hs_utmi_p2_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2595,7 +2657,7 @@ static struct clk usb_host_hs_utmi_p2_clk = { static struct clk usb_host_hs_utmi_p3_clk = { .name = "usb_host_hs_utmi_p3_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2605,7 +2667,7 @@ static struct clk usb_host_hs_utmi_p3_clk = { static struct clk usb_host_hs_hsic480m_p1_clk = { .name = "usb_host_hs_hsic480m_p1_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2615,7 +2677,7 @@ static struct clk usb_host_hs_hsic480m_p1_clk = { static struct clk usb_host_hs_hsic60m_p1_clk = { .name = "usb_host_hs_hsic60m_p1_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2625,7 +2687,7 @@ static struct clk usb_host_hs_hsic60m_p1_clk = { static struct clk usb_host_hs_hsic60m_p2_clk = { .name = "usb_host_hs_hsic60m_p2_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2635,7 +2697,7 @@ static struct clk usb_host_hs_hsic60m_p2_clk = { static struct clk usb_host_hs_hsic480m_p2_clk = { .name = "usb_host_hs_hsic480m_p2_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2645,7 +2707,7 @@ static struct clk usb_host_hs_hsic480m_p2_clk = { static struct clk usb_host_hs_func48mclk = { .name = "usb_host_hs_func48mclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2655,7 +2717,7 @@ static struct clk usb_host_hs_func48mclk = { static struct clk usb_host_hs_fck = { .name = "usb_host_hs_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l3_init_clkdm", @@ -2682,7 +2744,7 @@ static struct clk otg_60m_gfclk = { static struct clk usb_otg_hs_xclk = { .name = "usb_otg_hs_xclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_XCLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2692,17 +2754,17 @@ static struct clk usb_otg_hs_xclk = { static struct clk usb_otg_hs_ick = { .name = "usb_otg_hs_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l3_init_clkdm", - .parent = &l3_div_ck, + .parent = &otg_60m_gfclk, .recalc = &followparent_recalc, }; static struct clk usb_phy_cm_clk32k = { .name = "usb_phy_cm_clk32k", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_ALWON_USBPHY_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_CLK32K_SHIFT, .clkdm_name = "l4_ao_clkdm", @@ -2712,7 +2774,7 @@ static struct clk usb_phy_cm_clk32k = { static struct clk usb_tll_hs_usb_ch2_clk = { .name = "usb_tll_hs_usb_ch2_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2722,7 +2784,7 @@ static struct clk usb_tll_hs_usb_ch2_clk = { static struct clk usb_tll_hs_usb_ch0_clk = { .name = "usb_tll_hs_usb_ch0_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2732,7 +2794,7 @@ static struct clk usb_tll_hs_usb_ch0_clk = { static struct clk usb_tll_hs_usb_ch1_clk = { .name = "usb_tll_hs_usb_ch1_clk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT, .clkdm_name = "l3_init_clkdm", @@ -2742,7 +2804,7 @@ static struct clk usb_tll_hs_usb_ch1_clk = { static struct clk usb_tll_hs_ick = { .name = "usb_tll_hs_ick", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l3_init_clkdm", @@ -2751,8 +2813,8 @@ static struct clk usb_tll_hs_ick = { }; static const struct clksel_rate div2_14to18_rates[] = { - { .div = 14, .val = 0, .flags = RATE_IN_4430 }, - { .div = 18, .val = 1, .flags = RATE_IN_4430 }, + { .div = 14, .val = 0, .flags = RATE_IN_44XX }, + { .div = 18, .val = 1, .flags = RATE_IN_44XX }, { .div = 0 }, }; @@ -2775,7 +2837,7 @@ static struct clk usim_ck = { static struct clk usim_fclk = { .name = "usim_fclk", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_WKUP_USIM_CLKCTRL, .enable_bit = OMAP4430_OPTFCLKEN_FCLK_SHIFT, .clkdm_name = "l4_wkup_clkdm", @@ -2785,7 +2847,7 @@ static struct clk usim_fclk = { static struct clk usim_fck = { .name = "usim_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_WKUP_USIM_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_HWCTRL, .clkdm_name = "l4_wkup_clkdm", @@ -2795,7 +2857,7 @@ static struct clk usim_fck = { static struct clk wd_timer2_fck = { .name = "wd_timer2_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM_WKUP_WDT2_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "l4_wkup_clkdm", @@ -2805,7 +2867,7 @@ static struct clk wd_timer2_fck = { static struct clk wd_timer3_fck = { .name = "wd_timer3_fck", - .ops = &clkops_omap2_dflt, + .ops = &clkops_omap4_dflt_wait, .enable_reg = OMAP4430_CM1_ABE_WDT3_CLKCTRL, .enable_bit = OMAP4430_MODULEMODE_SWCTRL, .clkdm_name = "abe_clkdm", @@ -2850,19 +2912,39 @@ static struct clk trace_clk_div_ck = { /* SCRM aux clk nodes */ -static const struct clksel auxclk_sel[] = { +static const struct clksel auxclk_src_sel[] = { { .parent = &sys_clkin_ck, .rates = div_1_0_rates }, { .parent = &dpll_core_m3x2_ck, .rates = div_1_1_rates }, { .parent = &dpll_per_m3x2_ck, .rates = div_1_2_rates }, { .parent = NULL }, }; -static struct clk auxclk0_ck = { - .name = "auxclk0_ck", +static const struct clksel_rate div16_1to16_rates[] = { + { .div = 1, .val = 0, .flags = RATE_IN_44XX }, + { .div = 2, .val = 1, .flags = RATE_IN_44XX }, + { .div = 3, .val = 2, .flags = RATE_IN_44XX }, + { .div = 4, .val = 3, .flags = RATE_IN_44XX }, + { .div = 5, .val = 4, .flags = RATE_IN_44XX }, + { .div = 6, .val = 5, .flags = RATE_IN_44XX }, + { .div = 7, .val = 6, .flags = RATE_IN_44XX }, + { .div = 8, .val = 7, .flags = RATE_IN_44XX }, + { .div = 9, .val = 8, .flags = RATE_IN_44XX }, + { .div = 10, .val = 9, .flags = RATE_IN_44XX }, + { .div = 11, .val = 10, .flags = RATE_IN_44XX }, + { .div = 12, .val = 11, .flags = RATE_IN_44XX }, + { .div = 13, .val = 12, .flags = RATE_IN_44XX }, + { .div = 14, .val = 13, .flags = RATE_IN_44XX }, + { .div = 15, .val = 14, .flags = RATE_IN_44XX }, + { .div = 16, .val = 15, .flags = RATE_IN_44XX }, + { .div = 0 }, +}; + +static struct clk auxclk0_src_ck = { + .name = "auxclk0_src_ck", .parent = &sys_clkin_ck, .init = &omap2_init_clksel_parent, - .ops = &clkops_omap2_dflt, - .clksel = auxclk_sel, + .ops = &clkops_omap4_dflt_wait, + .clksel = auxclk_src_sel, .clksel_reg = OMAP4_SCRM_AUXCLK0, .clksel_mask = OMAP4_SRCSELECT_MASK, .recalc = &omap2_clksel_recalc, @@ -2870,12 +2952,29 @@ static struct clk auxclk0_ck = { .enable_bit = OMAP4_ENABLE_SHIFT, }; -static struct clk auxclk1_ck = { - .name = "auxclk1_ck", +static const struct clksel auxclk0_sel[] = { + { .parent = &auxclk0_src_ck, .rates = div16_1to16_rates }, + { .parent = NULL }, +}; + +static struct clk auxclk0_ck = { + .name = "auxclk0_ck", + .parent = &auxclk0_src_ck, + .clksel = auxclk0_sel, + .clksel_reg = OMAP4_SCRM_AUXCLK0, + .clksel_mask = OMAP4_CLKDIV_MASK, + .ops = &clkops_null, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate, +}; + +static struct clk auxclk1_src_ck = { + .name = "auxclk1_src_ck", .parent = &sys_clkin_ck, .init = &omap2_init_clksel_parent, - .ops = &clkops_omap2_dflt, - .clksel = auxclk_sel, + .ops = &clkops_omap4_dflt_wait, + .clksel = auxclk_src_sel, .clksel_reg = OMAP4_SCRM_AUXCLK1, .clksel_mask = OMAP4_SRCSELECT_MASK, .recalc = &omap2_clksel_recalc, @@ -2883,24 +2982,59 @@ static struct clk auxclk1_ck = { .enable_bit = OMAP4_ENABLE_SHIFT, }; -static struct clk auxclk2_ck = { - .name = "auxclk2_ck", +static const struct clksel auxclk1_sel[] = { + { .parent = &auxclk1_src_ck, .rates = div16_1to16_rates }, + { .parent = NULL }, +}; + +static struct clk auxclk1_ck = { + .name = "auxclk1_ck", + .parent = &auxclk1_src_ck, + .clksel = auxclk1_sel, + .clksel_reg = OMAP4_SCRM_AUXCLK1, + .clksel_mask = OMAP4_CLKDIV_MASK, + .ops = &clkops_null, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate, +}; + +static struct clk auxclk2_src_ck = { + .name = "auxclk2_src_ck", .parent = &sys_clkin_ck, .init = &omap2_init_clksel_parent, - .ops = &clkops_omap2_dflt, - .clksel = auxclk_sel, + .ops = &clkops_omap4_dflt_wait, + .clksel = auxclk_src_sel, .clksel_reg = OMAP4_SCRM_AUXCLK2, .clksel_mask = OMAP4_SRCSELECT_MASK, .recalc = &omap2_clksel_recalc, .enable_reg = OMAP4_SCRM_AUXCLK2, .enable_bit = OMAP4_ENABLE_SHIFT, }; -static struct clk auxclk3_ck = { - .name = "auxclk3_ck", + +static const struct clksel auxclk2_sel[] = { + { .parent = &auxclk2_src_ck, .rates = div16_1to16_rates }, + { .parent = NULL }, +}; + +static struct clk auxclk2_ck = { + .name = "auxclk2_ck", + .parent = &auxclk2_src_ck, + .clksel = auxclk2_sel, + .clksel_reg = OMAP4_SCRM_AUXCLK2, + .clksel_mask = OMAP4_CLKDIV_MASK, + .ops = &clkops_null, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate, +}; + +static struct clk auxclk3_src_ck = { + .name = "auxclk3_src_ck", .parent = &sys_clkin_ck, .init = &omap2_init_clksel_parent, - .ops = &clkops_omap2_dflt, - .clksel = auxclk_sel, + .ops = &clkops_omap4_dflt_wait, + .clksel = auxclk_src_sel, .clksel_reg = OMAP4_SCRM_AUXCLK3, .clksel_mask = OMAP4_SRCSELECT_MASK, .recalc = &omap2_clksel_recalc, @@ -2908,12 +3042,29 @@ static struct clk auxclk3_ck = { .enable_bit = OMAP4_ENABLE_SHIFT, }; -static struct clk auxclk4_ck = { - .name = "auxclk4_ck", +static const struct clksel auxclk3_sel[] = { + { .parent = &auxclk3_src_ck, .rates = div16_1to16_rates }, + { .parent = NULL }, +}; + +static struct clk auxclk3_ck = { + .name = "auxclk3_ck", + .parent = &auxclk3_src_ck, + .clksel = auxclk3_sel, + .clksel_reg = OMAP4_SCRM_AUXCLK3, + .clksel_mask = OMAP4_CLKDIV_MASK, + .ops = &clkops_null, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate, +}; + +static struct clk auxclk4_src_ck = { + .name = "auxclk4_src_ck", .parent = &sys_clkin_ck, .init = &omap2_init_clksel_parent, - .ops = &clkops_omap2_dflt, - .clksel = auxclk_sel, + .ops = &clkops_omap4_dflt_wait, + .clksel = auxclk_src_sel, .clksel_reg = OMAP4_SCRM_AUXCLK4, .clksel_mask = OMAP4_SRCSELECT_MASK, .recalc = &omap2_clksel_recalc, @@ -2921,12 +3072,29 @@ static struct clk auxclk4_ck = { .enable_bit = OMAP4_ENABLE_SHIFT, }; -static struct clk auxclk5_ck = { - .name = "auxclk5_ck", +static const struct clksel auxclk4_sel[] = { + { .parent = &auxclk4_src_ck, .rates = div16_1to16_rates }, + { .parent = NULL }, +}; + +static struct clk auxclk4_ck = { + .name = "auxclk4_ck", + .parent = &auxclk4_src_ck, + .clksel = auxclk4_sel, + .clksel_reg = OMAP4_SCRM_AUXCLK4, + .clksel_mask = OMAP4_CLKDIV_MASK, + .ops = &clkops_null, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate, +}; + +static struct clk auxclk5_src_ck = { + .name = "auxclk5_src_ck", .parent = &sys_clkin_ck, .init = &omap2_init_clksel_parent, - .ops = &clkops_omap2_dflt, - .clksel = auxclk_sel, + .ops = &clkops_omap4_dflt_wait, + .clksel = auxclk_src_sel, .clksel_reg = OMAP4_SCRM_AUXCLK5, .clksel_mask = OMAP4_SRCSELECT_MASK, .recalc = &omap2_clksel_recalc, @@ -2934,6 +3102,23 @@ static struct clk auxclk5_ck = { .enable_bit = OMAP4_ENABLE_SHIFT, }; +static const struct clksel auxclk5_sel[] = { + { .parent = &auxclk5_src_ck, .rates = div16_1to16_rates }, + { .parent = NULL }, +}; + +static struct clk auxclk5_ck = { + .name = "auxclk5_ck", + .parent = &auxclk5_src_ck, + .clksel = auxclk5_sel, + .clksel_reg = OMAP4_SCRM_AUXCLK5, + .clksel_mask = OMAP4_CLKDIV_MASK, + .ops = &clkops_null, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate, +}; + static const struct clksel auxclkreq_sel[] = { { .parent = &auxclk0_ck, .rates = div_1_0_rates }, { .parent = &auxclk1_ck, .rates = div_1_1_rates }, @@ -3010,289 +3195,448 @@ static struct clk auxclkreq5_ck = { .recalc = &omap2_clksel_recalc, }; +static struct clk smp_twd_443x = { + .name = "smp_twd", + .parent = &dpll_mpu_ck, + .ops = &clkops_null, + .fixed_div = 2, + .recalc = &omap_fixed_divisor_recalc, +}; + +static struct clk smp_twd_446x = { + .name = "smp_twd", + .parent = &virt_dpll_mpu_ck, + .ops = &clkops_null, + .fixed_div = 2, + .recalc = &omap_fixed_divisor_recalc, +}; + /* * clkdev */ static struct omap_clk omap44xx_clks[] = { - CLK(NULL, "extalt_clkin_ck", &extalt_clkin_ck, CK_443X), - CLK(NULL, "pad_clks_ck", &pad_clks_ck, CK_443X), - CLK(NULL, "pad_slimbus_core_clks_ck", &pad_slimbus_core_clks_ck, CK_443X), - CLK(NULL, "secure_32k_clk_src_ck", &secure_32k_clk_src_ck, CK_443X), - CLK(NULL, "slimbus_clk", &slimbus_clk, CK_443X), - CLK(NULL, "sys_32k_ck", &sys_32k_ck, CK_443X), - CLK(NULL, "virt_12000000_ck", &virt_12000000_ck, CK_443X), - CLK(NULL, "virt_13000000_ck", &virt_13000000_ck, CK_443X), - CLK(NULL, "virt_16800000_ck", &virt_16800000_ck, CK_443X), - CLK(NULL, "virt_19200000_ck", &virt_19200000_ck, CK_443X), - CLK(NULL, "virt_26000000_ck", &virt_26000000_ck, CK_443X), - CLK(NULL, "virt_27000000_ck", &virt_27000000_ck, CK_443X), - CLK(NULL, "virt_38400000_ck", &virt_38400000_ck, CK_443X), - CLK(NULL, "sys_clkin_ck", &sys_clkin_ck, CK_443X), - CLK(NULL, "tie_low_clock_ck", &tie_low_clock_ck, CK_443X), - CLK(NULL, "utmi_phy_clkout_ck", &utmi_phy_clkout_ck, CK_443X), - CLK(NULL, "xclk60mhsp1_ck", &xclk60mhsp1_ck, CK_443X), - CLK(NULL, "xclk60mhsp2_ck", &xclk60mhsp2_ck, CK_443X), - CLK(NULL, "xclk60motg_ck", &xclk60motg_ck, CK_443X), - CLK(NULL, "abe_dpll_bypass_clk_mux_ck", &abe_dpll_bypass_clk_mux_ck, CK_443X), - CLK(NULL, "abe_dpll_refclk_mux_ck", &abe_dpll_refclk_mux_ck, CK_443X), - CLK(NULL, "dpll_abe_ck", &dpll_abe_ck, CK_443X), - CLK(NULL, "dpll_abe_x2_ck", &dpll_abe_x2_ck, CK_443X), - CLK(NULL, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, CK_443X), - CLK(NULL, "abe_24m_fclk", &abe_24m_fclk, CK_443X), - CLK(NULL, "abe_clk", &abe_clk, CK_443X), - CLK(NULL, "aess_fclk", &aess_fclk, CK_443X), - CLK(NULL, "dpll_abe_m3x2_ck", &dpll_abe_m3x2_ck, CK_443X), - CLK(NULL, "core_hsd_byp_clk_mux_ck", &core_hsd_byp_clk_mux_ck, CK_443X), - CLK(NULL, "dpll_core_ck", &dpll_core_ck, CK_443X), - CLK(NULL, "dpll_core_x2_ck", &dpll_core_x2_ck, CK_443X), - CLK(NULL, "dpll_core_m6x2_ck", &dpll_core_m6x2_ck, CK_443X), - CLK(NULL, "dbgclk_mux_ck", &dbgclk_mux_ck, CK_443X), - CLK(NULL, "dpll_core_m2_ck", &dpll_core_m2_ck, CK_443X), - CLK(NULL, "ddrphy_ck", &ddrphy_ck, CK_443X), - CLK(NULL, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, CK_443X), - CLK(NULL, "div_core_ck", &div_core_ck, CK_443X), - CLK(NULL, "div_iva_hs_clk", &div_iva_hs_clk, CK_443X), - CLK(NULL, "div_mpu_hs_clk", &div_mpu_hs_clk, CK_443X), - CLK(NULL, "dpll_core_m4x2_ck", &dpll_core_m4x2_ck, CK_443X), - CLK(NULL, "dll_clk_div_ck", &dll_clk_div_ck, CK_443X), - CLK(NULL, "dpll_abe_m2_ck", &dpll_abe_m2_ck, CK_443X), - CLK(NULL, "dpll_core_m3x2_ck", &dpll_core_m3x2_ck, CK_443X), - CLK(NULL, "dpll_core_m7x2_ck", &dpll_core_m7x2_ck, CK_443X), - CLK(NULL, "iva_hsd_byp_clk_mux_ck", &iva_hsd_byp_clk_mux_ck, CK_443X), - CLK(NULL, "dpll_iva_ck", &dpll_iva_ck, CK_443X), - CLK(NULL, "dpll_iva_x2_ck", &dpll_iva_x2_ck, CK_443X), - CLK(NULL, "dpll_iva_m4x2_ck", &dpll_iva_m4x2_ck, CK_443X), - CLK(NULL, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, CK_443X), - CLK(NULL, "dpll_mpu_ck", &dpll_mpu_ck, CK_443X), - CLK(NULL, "dpll_mpu_m2_ck", &dpll_mpu_m2_ck, CK_443X), - CLK(NULL, "per_hs_clk_div_ck", &per_hs_clk_div_ck, CK_443X), - CLK(NULL, "per_hsd_byp_clk_mux_ck", &per_hsd_byp_clk_mux_ck, CK_443X), - CLK(NULL, "dpll_per_ck", &dpll_per_ck, CK_443X), - CLK(NULL, "dpll_per_m2_ck", &dpll_per_m2_ck, CK_443X), - CLK(NULL, "dpll_per_x2_ck", &dpll_per_x2_ck, CK_443X), - CLK(NULL, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, CK_443X), - CLK(NULL, "dpll_per_m3x2_ck", &dpll_per_m3x2_ck, CK_443X), - CLK(NULL, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, CK_443X), - CLK(NULL, "dpll_per_m5x2_ck", &dpll_per_m5x2_ck, CK_443X), - CLK(NULL, "dpll_per_m6x2_ck", &dpll_per_m6x2_ck, CK_443X), - CLK(NULL, "dpll_per_m7x2_ck", &dpll_per_m7x2_ck, CK_443X), - CLK(NULL, "dpll_unipro_ck", &dpll_unipro_ck, CK_443X), - CLK(NULL, "dpll_unipro_x2_ck", &dpll_unipro_x2_ck, CK_443X), - CLK(NULL, "dpll_unipro_m2x2_ck", &dpll_unipro_m2x2_ck, CK_443X), - CLK(NULL, "usb_hs_clk_div_ck", &usb_hs_clk_div_ck, CK_443X), - CLK(NULL, "dpll_usb_ck", &dpll_usb_ck, CK_443X), - CLK(NULL, "dpll_usb_clkdcoldo_ck", &dpll_usb_clkdcoldo_ck, CK_443X), - CLK(NULL, "dpll_usb_m2_ck", &dpll_usb_m2_ck, CK_443X), - CLK(NULL, "ducati_clk_mux_ck", &ducati_clk_mux_ck, CK_443X), - CLK(NULL, "func_12m_fclk", &func_12m_fclk, CK_443X), - CLK(NULL, "func_24m_clk", &func_24m_clk, CK_443X), - CLK(NULL, "func_24mc_fclk", &func_24mc_fclk, CK_443X), - CLK(NULL, "func_48m_fclk", &func_48m_fclk, CK_443X), - CLK(NULL, "func_48mc_fclk", &func_48mc_fclk, CK_443X), - CLK(NULL, "func_64m_fclk", &func_64m_fclk, CK_443X), - CLK(NULL, "func_96m_fclk", &func_96m_fclk, CK_443X), - CLK(NULL, "hsmmc6_fclk", &hsmmc6_fclk, CK_443X), - CLK(NULL, "init_60m_fclk", &init_60m_fclk, CK_443X), - CLK(NULL, "l3_div_ck", &l3_div_ck, CK_443X), - CLK(NULL, "l4_div_ck", &l4_div_ck, CK_443X), - CLK(NULL, "lp_clk_div_ck", &lp_clk_div_ck, CK_443X), - CLK(NULL, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, CK_443X), - CLK(NULL, "per_abe_nc_fclk", &per_abe_nc_fclk, CK_443X), - CLK(NULL, "mcasp2_fclk", &mcasp2_fclk, CK_443X), - CLK(NULL, "mcasp3_fclk", &mcasp3_fclk, CK_443X), - CLK(NULL, "ocp_abe_iclk", &ocp_abe_iclk, CK_443X), - CLK(NULL, "per_abe_24m_fclk", &per_abe_24m_fclk, CK_443X), - CLK(NULL, "pmd_stm_clock_mux_ck", &pmd_stm_clock_mux_ck, CK_443X), - CLK(NULL, "pmd_trace_clk_mux_ck", &pmd_trace_clk_mux_ck, CK_443X), - CLK(NULL, "syc_clk_div_ck", &syc_clk_div_ck, CK_443X), - CLK(NULL, "aes1_fck", &aes1_fck, CK_443X), - CLK(NULL, "aes2_fck", &aes2_fck, CK_443X), - CLK(NULL, "aess_fck", &aess_fck, CK_443X), - CLK(NULL, "bandgap_fclk", &bandgap_fclk, CK_443X), - CLK(NULL, "des3des_fck", &des3des_fck, CK_443X), - CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X), - CLK(NULL, "dmic_fck", &dmic_fck, CK_443X), - CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), - CLK("omapdss_dss", "sys_clk", &dss_sys_clk, CK_443X), - CLK("omapdss_dss", "tv_clk", &dss_tv_clk, CK_443X), - CLK("omapdss_dss", "video_clk", &dss_48mhz_clk, CK_443X), - CLK("omapdss_dss", "fck", &dss_dss_clk, CK_443X), - CLK("omapdss_dss", "ick", &dss_fck, CK_443X), - CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_443X), - CLK(NULL, "emif1_fck", &emif1_fck, CK_443X), - CLK(NULL, "emif2_fck", &emif2_fck, CK_443X), - CLK(NULL, "fdif_fck", &fdif_fck, CK_443X), - CLK(NULL, "fpka_fck", &fpka_fck, CK_443X), - CLK(NULL, "gpio1_dbclk", &gpio1_dbclk, CK_443X), - CLK(NULL, "gpio1_ick", &gpio1_ick, CK_443X), - CLK(NULL, "gpio2_dbclk", &gpio2_dbclk, CK_443X), - CLK(NULL, "gpio2_ick", &gpio2_ick, CK_443X), - CLK(NULL, "gpio3_dbclk", &gpio3_dbclk, CK_443X), - CLK(NULL, "gpio3_ick", &gpio3_ick, CK_443X), - CLK(NULL, "gpio4_dbclk", &gpio4_dbclk, CK_443X), - CLK(NULL, "gpio4_ick", &gpio4_ick, CK_443X), - CLK(NULL, "gpio5_dbclk", &gpio5_dbclk, CK_443X), - CLK(NULL, "gpio5_ick", &gpio5_ick, CK_443X), - CLK(NULL, "gpio6_dbclk", &gpio6_dbclk, CK_443X), - CLK(NULL, "gpio6_ick", &gpio6_ick, CK_443X), - CLK(NULL, "gpmc_ick", &gpmc_ick, CK_443X), - CLK(NULL, "gpu_fck", &gpu_fck, CK_443X), - CLK("omap2_hdq.0", "fck", &hdq1w_fck, CK_443X), - CLK(NULL, "hsi_fck", &hsi_fck, CK_443X), - CLK("omap_i2c.1", "fck", &i2c1_fck, CK_443X), - CLK("omap_i2c.2", "fck", &i2c2_fck, CK_443X), - CLK("omap_i2c.3", "fck", &i2c3_fck, CK_443X), - CLK("omap_i2c.4", "fck", &i2c4_fck, CK_443X), - CLK(NULL, "ipu_fck", &ipu_fck, CK_443X), - CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X), - CLK(NULL, "iss_fck", &iss_fck, CK_443X), - CLK(NULL, "iva_fck", &iva_fck, CK_443X), - CLK(NULL, "kbd_fck", &kbd_fck, CK_443X), - CLK(NULL, "l3_instr_ick", &l3_instr_ick, CK_443X), - CLK(NULL, "l3_main_3_ick", &l3_main_3_ick, CK_443X), - CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck, CK_443X), - CLK(NULL, "mcasp_fck", &mcasp_fck, CK_443X), - CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck, CK_443X), - CLK("omap-mcbsp.1", "fck", &mcbsp1_fck, CK_443X), - CLK(NULL, "mcbsp2_sync_mux_ck", &mcbsp2_sync_mux_ck, CK_443X), - CLK("omap-mcbsp.2", "fck", &mcbsp2_fck, CK_443X), - CLK(NULL, "mcbsp3_sync_mux_ck", &mcbsp3_sync_mux_ck, CK_443X), - CLK("omap-mcbsp.3", "fck", &mcbsp3_fck, CK_443X), - CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck, CK_443X), - CLK("omap-mcbsp.4", "fck", &mcbsp4_fck, CK_443X), - CLK(NULL, "mcpdm_fck", &mcpdm_fck, CK_443X), - CLK("omap2_mcspi.1", "fck", &mcspi1_fck, CK_443X), - CLK("omap2_mcspi.2", "fck", &mcspi2_fck, CK_443X), - CLK("omap2_mcspi.3", "fck", &mcspi3_fck, CK_443X), - CLK("omap2_mcspi.4", "fck", &mcspi4_fck, CK_443X), - CLK("omap_hsmmc.0", "fck", &mmc1_fck, CK_443X), - CLK("omap_hsmmc.1", "fck", &mmc2_fck, CK_443X), - CLK("omap_hsmmc.2", "fck", &mmc3_fck, CK_443X), - CLK("omap_hsmmc.3", "fck", &mmc4_fck, CK_443X), - CLK("omap_hsmmc.4", "fck", &mmc5_fck, CK_443X), - CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_443X), - CLK(NULL, "ocp2scp_usb_phy_ick", &ocp2scp_usb_phy_ick, CK_443X), - CLK(NULL, "ocp_wp_noc_ick", &ocp_wp_noc_ick, CK_443X), - CLK("omap_rng", "ick", &rng_ick, CK_443X), - CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_443X), - CLK(NULL, "sl2if_ick", &sl2if_ick, CK_443X), - CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_443X), - CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_443X), - CLK(NULL, "slimbus1_fclk_2", &slimbus1_fclk_2, CK_443X), - CLK(NULL, "slimbus1_slimbus_clk", &slimbus1_slimbus_clk, CK_443X), - CLK(NULL, "slimbus1_fck", &slimbus1_fck, CK_443X), - CLK(NULL, "slimbus2_fclk_1", &slimbus2_fclk_1, CK_443X), - CLK(NULL, "slimbus2_fclk_0", &slimbus2_fclk_0, CK_443X), - CLK(NULL, "slimbus2_slimbus_clk", &slimbus2_slimbus_clk, CK_443X), - CLK(NULL, "slimbus2_fck", &slimbus2_fck, CK_443X), - CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck, CK_443X), - CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck, CK_443X), - CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck, CK_443X), - CLK(NULL, "gpt1_fck", &timer1_fck, CK_443X), - CLK(NULL, "gpt10_fck", &timer10_fck, CK_443X), - CLK(NULL, "gpt11_fck", &timer11_fck, CK_443X), - CLK(NULL, "gpt2_fck", &timer2_fck, CK_443X), - CLK(NULL, "gpt3_fck", &timer3_fck, CK_443X), - CLK(NULL, "gpt4_fck", &timer4_fck, CK_443X), - CLK(NULL, "gpt5_fck", &timer5_fck, CK_443X), - CLK(NULL, "gpt6_fck", &timer6_fck, CK_443X), - CLK(NULL, "gpt7_fck", &timer7_fck, CK_443X), - CLK(NULL, "gpt8_fck", &timer8_fck, CK_443X), - CLK(NULL, "gpt9_fck", &timer9_fck, CK_443X), - CLK(NULL, "uart1_fck", &uart1_fck, CK_443X), - CLK(NULL, "uart2_fck", &uart2_fck, CK_443X), - CLK(NULL, "uart3_fck", &uart3_fck, CK_443X), - CLK(NULL, "uart4_fck", &uart4_fck, CK_443X), - CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X), - CLK("usbhs-omap.0", "fs_fck", &usb_host_fs_fck, CK_443X), - CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X), - CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk, CK_443X), - CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk, CK_443X), - CLK(NULL, "usb_host_hs_utmi_p2_clk", &usb_host_hs_utmi_p2_clk, CK_443X), - CLK(NULL, "usb_host_hs_utmi_p3_clk", &usb_host_hs_utmi_p3_clk, CK_443X), - CLK(NULL, "usb_host_hs_hsic480m_p1_clk", &usb_host_hs_hsic480m_p1_clk, CK_443X), - CLK(NULL, "usb_host_hs_hsic60m_p1_clk", &usb_host_hs_hsic60m_p1_clk, CK_443X), - CLK(NULL, "usb_host_hs_hsic60m_p2_clk", &usb_host_hs_hsic60m_p2_clk, CK_443X), - CLK(NULL, "usb_host_hs_hsic480m_p2_clk", &usb_host_hs_hsic480m_p2_clk, CK_443X), - CLK(NULL, "usb_host_hs_func48mclk", &usb_host_hs_func48mclk, CK_443X), - CLK(NULL, "usb_host_hs_fck", &usb_host_hs_fck, CK_443X), - CLK("usbhs-omap.0", "hs_fck", &usb_host_hs_fck, CK_443X), - CLK("usbhs-omap.0", "usbhost_ick", &dummy_ck, CK_443X), - CLK(NULL, "otg_60m_gfclk", &otg_60m_gfclk, CK_443X), - CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk, CK_443X), - CLK("musb-omap2430", "ick", &usb_otg_hs_ick, CK_443X), - CLK(NULL, "usb_phy_cm_clk32k", &usb_phy_cm_clk32k, CK_443X), - CLK(NULL, "usb_tll_hs_usb_ch2_clk", &usb_tll_hs_usb_ch2_clk, CK_443X), - CLK(NULL, "usb_tll_hs_usb_ch0_clk", &usb_tll_hs_usb_ch0_clk, CK_443X), - CLK(NULL, "usb_tll_hs_usb_ch1_clk", &usb_tll_hs_usb_ch1_clk, CK_443X), - CLK(NULL, "usb_tll_hs_ick", &usb_tll_hs_ick, CK_443X), - CLK("usbhs-omap.0", "usbtll_ick", &usb_tll_hs_ick, CK_443X), - CLK("usbhs-omap.0", "usbtll_fck", &dummy_ck, CK_443X), - CLK(NULL, "usim_ck", &usim_ck, CK_443X), - CLK(NULL, "usim_fclk", &usim_fclk, CK_443X), - CLK(NULL, "usim_fck", &usim_fck, CK_443X), - CLK("omap_wdt", "fck", &wd_timer2_fck, CK_443X), - CLK(NULL, "mailboxes_ick", &dummy_ck, CK_443X), - CLK(NULL, "wd_timer3_fck", &wd_timer3_fck, CK_443X), - CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck, CK_443X), - CLK(NULL, "trace_clk_div_ck", &trace_clk_div_ck, CK_443X), - CLK(NULL, "gpmc_ck", &dummy_ck, CK_443X), - CLK(NULL, "gpt1_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt2_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt3_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt4_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt5_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt6_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt7_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt8_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt9_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt10_ick", &dummy_ck, CK_443X), - CLK(NULL, "gpt11_ick", &dummy_ck, CK_443X), - CLK("omap_i2c.1", "ick", &dummy_ck, CK_443X), - CLK("omap_i2c.2", "ick", &dummy_ck, CK_443X), - CLK("omap_i2c.3", "ick", &dummy_ck, CK_443X), - CLK("omap_i2c.4", "ick", &dummy_ck, CK_443X), - CLK("omap_hsmmc.0", "ick", &dummy_ck, CK_443X), - CLK("omap_hsmmc.1", "ick", &dummy_ck, CK_443X), - CLK("omap_hsmmc.2", "ick", &dummy_ck, CK_443X), - CLK("omap_hsmmc.3", "ick", &dummy_ck, CK_443X), - CLK("omap_hsmmc.4", "ick", &dummy_ck, CK_443X), - CLK("omap-mcbsp.1", "ick", &dummy_ck, CK_443X), - CLK("omap-mcbsp.2", "ick", &dummy_ck, CK_443X), - CLK("omap-mcbsp.3", "ick", &dummy_ck, CK_443X), - CLK("omap-mcbsp.4", "ick", &dummy_ck, CK_443X), - CLK("omap2_mcspi.1", "ick", &dummy_ck, CK_443X), - CLK("omap2_mcspi.2", "ick", &dummy_ck, CK_443X), - CLK("omap2_mcspi.3", "ick", &dummy_ck, CK_443X), - CLK("omap2_mcspi.4", "ick", &dummy_ck, CK_443X), - CLK(NULL, "uart1_ick", &dummy_ck, CK_443X), - CLK(NULL, "uart2_ick", &dummy_ck, CK_443X), - CLK(NULL, "uart3_ick", &dummy_ck, CK_443X), - CLK(NULL, "uart4_ick", &dummy_ck, CK_443X), - CLK("omap_wdt", "ick", &dummy_ck, CK_443X), - CLK(NULL, "auxclk0_ck", &auxclk0_ck, CK_443X), - CLK(NULL, "auxclk1_ck", &auxclk1_ck, CK_443X), - CLK(NULL, "auxclk2_ck", &auxclk2_ck, CK_443X), - CLK(NULL, "auxclk3_ck", &auxclk3_ck, CK_443X), - CLK(NULL, "auxclk4_ck", &auxclk4_ck, CK_443X), - CLK(NULL, "auxclk5_ck", &auxclk5_ck, CK_443X), - CLK(NULL, "auxclkreq0_ck", &auxclkreq0_ck, CK_443X), - CLK(NULL, "auxclkreq1_ck", &auxclkreq1_ck, CK_443X), - CLK(NULL, "auxclkreq2_ck", &auxclkreq2_ck, CK_443X), - CLK(NULL, "auxclkreq3_ck", &auxclkreq3_ck, CK_443X), - CLK(NULL, "auxclkreq4_ck", &auxclkreq4_ck, CK_443X), - CLK(NULL, "auxclkreq5_ck", &auxclkreq5_ck, CK_443X), -}; + CLK(NULL, "extalt_clkin_ck", &extalt_clkin_ck, CK_44XX), + CLK(NULL, "pad_clks_ck", &pad_clks_ck, CK_44XX), + CLK(NULL, "pad_slimbus_core_clks_ck", &pad_slimbus_core_clks_ck, CK_44XX), + CLK(NULL, "secure_32k_clk_src_ck", &secure_32k_clk_src_ck, CK_44XX), + CLK(NULL, "slimbus_clk", &slimbus_clk, CK_44XX), + CLK(NULL, "sys_32k_ck", &sys_32k_ck, CK_44XX), + CLK(NULL, "virt_12000000_ck", &virt_12000000_ck, CK_44XX), + CLK(NULL, "virt_13000000_ck", &virt_13000000_ck, CK_44XX), + CLK(NULL, "virt_16800000_ck", &virt_16800000_ck, CK_44XX), + CLK(NULL, "virt_19200000_ck", &virt_19200000_ck, CK_44XX), + CLK(NULL, "virt_26000000_ck", &virt_26000000_ck, CK_44XX), + CLK(NULL, "virt_27000000_ck", &virt_27000000_ck, CK_44XX), + CLK(NULL, "virt_38400000_ck", &virt_38400000_ck, CK_44XX), + CLK(NULL, "sys_clkin_ck", &sys_clkin_ck, CK_44XX), + CLK(NULL, "tie_low_clock_ck", &tie_low_clock_ck, CK_44XX), + CLK(NULL, "utmi_phy_clkout_ck", &utmi_phy_clkout_ck, CK_44XX), + CLK(NULL, "xclk60mhsp1_ck", &xclk60mhsp1_ck, CK_44XX), + CLK(NULL, "xclk60mhsp2_ck", &xclk60mhsp2_ck, CK_44XX), + CLK(NULL, "xclk60motg_ck", &xclk60motg_ck, CK_44XX), + CLK(NULL, "abe_dpll_bypass_clk_mux_ck", &abe_dpll_bypass_clk_mux_ck, CK_44XX), + CLK(NULL, "abe_dpll_refclk_mux_ck", &abe_dpll_refclk_mux_ck, CK_44XX), + CLK(NULL, "dpll_abe_ck", &dpll_abe_ck, CK_44XX), + CLK(NULL, "dpll_abe_x2_ck", &dpll_abe_x2_ck, CK_44XX), + CLK(NULL, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, CK_44XX), + CLK(NULL, "abe_24m_fclk", &abe_24m_fclk, CK_44XX), + CLK(NULL, "abe_clk", &abe_clk, CK_44XX), + CLK(NULL, "aess_fclk", &aess_fclk, CK_44XX), + CLK(NULL, "dpll_abe_m3x2_ck", &dpll_abe_m3x2_ck, CK_44XX), + CLK(NULL, "core_hsd_byp_clk_mux_ck", &core_hsd_byp_clk_mux_ck, CK_44XX), + CLK(NULL, "dpll_core_ck", &dpll_core_ck, CK_44XX), + CLK(NULL, "dpll_core_x2_ck", &dpll_core_x2_ck, CK_44XX), + CLK(NULL, "dpll_core_m6x2_ck", &dpll_core_m6x2_ck, CK_44XX), + CLK(NULL, "dbgclk_mux_ck", &dbgclk_mux_ck, CK_44XX), + CLK(NULL, "dpll_core_m2_ck", &dpll_core_m2_ck, CK_44XX), + CLK(NULL, "ddrphy_ck", &ddrphy_ck, CK_44XX), + CLK(NULL, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, CK_44XX), + CLK(NULL, "virt_l3_ck", &virt_l3_ck, CK_44XX), + CLK(NULL, "div_core_ck", &div_core_ck, CK_44XX), + CLK(NULL, "div_iva_hs_clk", &div_iva_hs_clk, CK_44XX), + CLK(NULL, "div_mpu_hs_clk", &div_mpu_hs_clk, CK_44XX), + CLK(NULL, "dpll_core_m4x2_ck", &dpll_core_m4x2_ck, CK_44XX), + CLK(NULL, "dll_clk_div_ck", &dll_clk_div_ck, CK_44XX), + CLK(NULL, "dpll_abe_m2_ck", &dpll_abe_m2_ck, CK_44XX), + CLK(NULL, "dpll_core_m3x2_ck", &dpll_core_m3x2_ck, CK_44XX), + CLK(NULL, "dpll_core_m7x2_ck", &dpll_core_m7x2_ck, CK_44XX), + CLK(NULL, "iva_hsd_byp_clk_mux_ck", &iva_hsd_byp_clk_mux_ck, CK_44XX), + CLK(NULL, "dpll_iva_ck", &dpll_iva_ck, CK_44XX), + CLK(NULL, "dpll_iva_x2_ck", &dpll_iva_x2_ck, CK_44XX), + CLK(NULL, "dpll_iva_m4x2_ck", &dpll_iva_m4x2_ck, CK_44XX), + CLK(NULL, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, CK_44XX), + CLK(NULL, "dpll_mpu_ck", &dpll_mpu_ck, CK_44XX), + CLK(NULL, "virt_dpll_mpu_ck", &virt_dpll_mpu_ck, CK_446X), + CLK(NULL, "dpll_mpu_m2_ck", &dpll_mpu_m2_ck, CK_44XX), + CLK(NULL, "per_hs_clk_div_ck", &per_hs_clk_div_ck, CK_44XX), + CLK(NULL, "per_hsd_byp_clk_mux_ck", &per_hsd_byp_clk_mux_ck, CK_44XX), + CLK(NULL, "dpll_per_ck", &dpll_per_ck, CK_44XX), + CLK(NULL, "dpll_per_m2_ck", &dpll_per_m2_ck, CK_44XX), + CLK(NULL, "dpll_per_x2_ck", &dpll_per_x2_ck, CK_44XX), + CLK(NULL, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, CK_44XX), + CLK(NULL, "dpll_per_m3x2_ck", &dpll_per_m3x2_ck, CK_44XX), + CLK(NULL, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, CK_44XX), + CLK(NULL, "dpll_per_m5x2_ck", &dpll_per_m5x2_ck, CK_44XX), + CLK(NULL, "dpll_per_m6x2_ck", &dpll_per_m6x2_ck, CK_44XX), + CLK(NULL, "dpll_per_m7x2_ck", &dpll_per_m7x2_ck, CK_44XX), + CLK(NULL, "dpll_unipro_ck", &dpll_unipro_ck, CK_44XX), + CLK(NULL, "dpll_unipro_x2_ck", &dpll_unipro_x2_ck, CK_44XX), + CLK(NULL, "dpll_unipro_m2x2_ck", &dpll_unipro_m2x2_ck, CK_44XX), + CLK(NULL, "usb_hs_clk_div_ck", &usb_hs_clk_div_ck, CK_44XX), + CLK(NULL, "dpll_usb_ck", &dpll_usb_ck, CK_44XX), + CLK(NULL, "dpll_usb_clkdcoldo_ck", &dpll_usb_clkdcoldo_ck, CK_44XX), + CLK(NULL, "dpll_usb_m2_ck", &dpll_usb_m2_ck, CK_44XX), + CLK(NULL, "ducati_clk_mux_ck", &ducati_clk_mux_ck, CK_44XX), + CLK(NULL, "func_12m_fclk", &func_12m_fclk, CK_44XX), + CLK(NULL, "func_24m_clk", &func_24m_clk, CK_44XX), + CLK(NULL, "func_24mc_fclk", &func_24mc_fclk, CK_44XX), + CLK(NULL, "func_48m_fclk", &func_48m_fclk, CK_44XX), + CLK(NULL, "func_48mc_fclk", &func_48mc_fclk, CK_44XX), + CLK(NULL, "func_64m_fclk", &func_64m_fclk, CK_44XX), + CLK(NULL, "func_96m_fclk", &func_96m_fclk, CK_44XX), + CLK(NULL, "hsmmc6_fclk", &hsmmc6_fclk, CK_44XX), + CLK(NULL, "init_60m_fclk", &init_60m_fclk, CK_44XX), + CLK(NULL, "l3_div_ck", &l3_div_ck, CK_44XX), + CLK(NULL, "l4_div_ck", &l4_div_ck, CK_44XX), + CLK(NULL, "lp_clk_div_ck", &lp_clk_div_ck, CK_44XX), + CLK(NULL, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck, CK_44XX), + CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X), + CLK(NULL, "per_abe_nc_fclk", &per_abe_nc_fclk, CK_44XX), + CLK(NULL, "mcasp2_fclk", &mcasp2_fclk, CK_44XX), + CLK(NULL, "mcasp3_fclk", &mcasp3_fclk, CK_44XX), + CLK(NULL, "ocp_abe_iclk", &ocp_abe_iclk, CK_44XX), + CLK(NULL, "per_abe_24m_fclk", &per_abe_24m_fclk, CK_44XX), + CLK(NULL, "pmd_stm_clock_mux_ck", &pmd_stm_clock_mux_ck, CK_44XX), + CLK(NULL, "pmd_trace_clk_mux_ck", &pmd_trace_clk_mux_ck, CK_44XX), + CLK(NULL, "syc_clk_div_ck", &syc_clk_div_ck, CK_44XX), + CLK(NULL, "aes1_fck", &aes1_fck, CK_44XX), + CLK(NULL, "aes2_fck", &aes2_fck, CK_44XX), + CLK(NULL, "aess_fck", &aess_fck, CK_44XX), + CLK("omap_temp_sensor.0", "fck", &bandgap_fclk, CK_443X), + CLK("omap_temp_sensor.0", "fck", &bandgap_ts_fclk, CK_446X), + CLK(NULL, "des3des_fck", &des3des_fck, CK_44XX), + CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_44XX), + CLK(NULL, "dmic_fck", &dmic_fck, CK_44XX), + CLK(NULL, "dsp_fck", &dsp_fck, CK_44XX), + CLK(NULL, "sys_clk", &dss_sys_clk, CK_44XX), + CLK(NULL, "tv_clk", &dss_tv_clk, CK_44XX), + CLK(NULL, "video_clk", &dss_48mhz_clk, CK_44XX), + CLK(NULL, "fck", &dss_dss_clk, CK_44XX), + CLK(NULL, "ick", &dss_fck, CK_44XX), + CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_44XX), + CLK(NULL, "emif1_fck", &emif1_fck, CK_44XX), + CLK(NULL, "emif2_fck", &emif2_fck, CK_44XX), + CLK(NULL, "fdif_fck", &fdif_fck, CK_44XX), + CLK(NULL, "fpka_fck", &fpka_fck, CK_44XX), + CLK(NULL, "gpio1_dbclk", &gpio1_dbclk, CK_44XX), + CLK(NULL, "gpio1_ick", &gpio1_ick, CK_44XX), + CLK(NULL, "gpio2_dbclk", &gpio2_dbclk, CK_44XX), + CLK(NULL, "gpio2_ick", &gpio2_ick, CK_44XX), + CLK(NULL, "gpio3_dbclk", &gpio3_dbclk, CK_44XX), + CLK(NULL, "gpio3_ick", &gpio3_ick, CK_44XX), + CLK(NULL, "gpio4_dbclk", &gpio4_dbclk, CK_44XX), + CLK(NULL, "gpio4_ick", &gpio4_ick, CK_44XX), + CLK(NULL, "gpio5_dbclk", &gpio5_dbclk, CK_44XX), + CLK(NULL, "gpio5_ick", &gpio5_ick, CK_44XX), + CLK(NULL, "gpio6_dbclk", &gpio6_dbclk, CK_44XX), + CLK(NULL, "gpio6_ick", &gpio6_ick, CK_44XX), + CLK(NULL, "gpmc_ick", &gpmc_ick, CK_44XX), + CLK(NULL, "gpu_fck", &gpu_fck, CK_44XX), + CLK("omap2_hdq.0", "fck", &hdq1w_fck, CK_44XX), + CLK(NULL, "hsi_fck", &hsi_fck, CK_44XX), + CLK("omap_i2c.1", "fck", &i2c1_fck, CK_44XX), + CLK("omap_i2c.2", "fck", &i2c2_fck, CK_44XX), + CLK("omap_i2c.3", "fck", &i2c3_fck, CK_44XX), + CLK("omap_i2c.4", "fck", &i2c4_fck, CK_44XX), + CLK(NULL, "ipu_fck", &ipu_fck, CK_44XX), + CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_44XX), + CLK(NULL, "iss_fck", &iss_fck, CK_44XX), + CLK(NULL, "iva_fck", &iva_fck, CK_44XX), + CLK(NULL, "kbd_fck", &kbd_fck, CK_44XX), + CLK(NULL, "l3_instr_ick", &l3_instr_ick, CK_44XX), + CLK(NULL, "l3_main_3_ick", &l3_main_3_ick, CK_44XX), + CLK(NULL, "mcasp_sync_mux_ck", &mcasp_sync_mux_ck, CK_44XX), + CLK(NULL, "mcasp_fck", &mcasp_fck, CK_44XX), + CLK(NULL, "mcbsp1_sync_mux_ck", &mcbsp1_sync_mux_ck, CK_44XX), + CLK("omap-mcbsp.1", "fck", &mcbsp1_fck, CK_44XX), + CLK(NULL, "mcbsp2_sync_mux_ck", &mcbsp2_sync_mux_ck, CK_44XX), + CLK("omap-mcbsp.2", "fck", &mcbsp2_fck, CK_44XX), + CLK(NULL, "mcbsp3_sync_mux_ck", &mcbsp3_sync_mux_ck, CK_44XX), + CLK("omap-mcbsp.3", "fck", &mcbsp3_fck, CK_44XX), + CLK(NULL, "mcbsp4_sync_mux_ck", &mcbsp4_sync_mux_ck, CK_44XX), + CLK("omap-mcbsp.4", "fck", &mcbsp4_fck, CK_44XX), + CLK(NULL, "mcpdm_fck", &mcpdm_fck, CK_44XX), + CLK("omap2_mcspi.1", "fck", &mcspi1_fck, CK_44XX), + CLK("omap2_mcspi.2", "fck", &mcspi2_fck, CK_44XX), + CLK("omap2_mcspi.3", "fck", &mcspi3_fck, CK_44XX), + CLK("omap2_mcspi.4", "fck", &mcspi4_fck, CK_44XX), + CLK("omap_hsmmc.0", "fck", &mmc1_fck, CK_44XX), + CLK("omap_hsmmc.1", "fck", &mmc2_fck, CK_44XX), + CLK("omap_hsmmc.2", "fck", &mmc3_fck, CK_44XX), + CLK("omap_hsmmc.3", "fck", &mmc4_fck, CK_44XX), + CLK("omap_hsmmc.4", "fck", &mmc5_fck, CK_44XX), + CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_44XX), + CLK(NULL, "ocp2scp_usb_phy_ick", &ocp2scp_usb_phy_ick, CK_44XX), + CLK(NULL, "ocp_wp_noc_ick", &ocp_wp_noc_ick, CK_44XX), + CLK("omap_rng", "ick", &rng_ick, CK_44XX), + CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_44XX), + CLK(NULL, "sl2if_ick", &sl2if_ick, CK_44XX), + CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_44XX), + CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_44XX), + CLK(NULL, "slimbus1_fclk_2", &slimbus1_fclk_2, CK_44XX), + CLK(NULL, "slimbus1_slimbus_clk", &slimbus1_slimbus_clk, CK_44XX), + CLK(NULL, "slimbus1_fck", &slimbus1_fck, CK_44XX), + CLK(NULL, "slimbus2_fclk_1", &slimbus2_fclk_1, CK_44XX), + CLK(NULL, "slimbus2_fclk_0", &slimbus2_fclk_0, CK_44XX), + CLK(NULL, "slimbus2_slimbus_clk", &slimbus2_slimbus_clk, CK_44XX), + CLK(NULL, "slimbus2_fck", &slimbus2_fck, CK_44XX), + CLK(NULL, "smartreflex_core_fck", &smartreflex_core_fck, CK_44XX), + CLK(NULL, "smartreflex_iva_fck", &smartreflex_iva_fck, CK_44XX), + CLK(NULL, "smartreflex_mpu_fck", &smartreflex_mpu_fck, CK_44XX), + CLK("omap_timer.1", "fck", &timer1_fck, CK_44XX), + CLK("omap_timer.10", "fck", &timer10_fck, CK_44XX), + CLK("omap_timer.11", "fck", &timer11_fck, CK_44XX), + CLK("omap_timer.2", "fck", &timer2_fck, CK_44XX), + CLK("omap_timer.3", "fck", &timer3_fck, CK_44XX), + CLK("omap_timer.4", "fck", &timer4_fck, CK_44XX), + CLK("omap_timer.5", "fck", &timer5_fck, CK_44XX), + CLK("omap_timer.6", "fck", &timer6_fck, CK_44XX), + CLK("omap_timer.7", "fck", &timer7_fck, CK_44XX), + CLK("omap_timer.8", "fck", &timer8_fck, CK_44XX), + CLK("omap_timer.9", "fck", &timer9_fck, CK_44XX), + CLK(NULL, "uart1_fck", &uart1_fck, CK_44XX), + CLK(NULL, "uart2_fck", &uart2_fck, CK_44XX), + CLK(NULL, "uart3_fck", &uart3_fck, CK_44XX), + CLK(NULL, "uart4_fck", &uart4_fck, CK_44XX), + CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_44XX), + CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck, CK_44XX), + CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_44XX), + CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk, CK_44XX), + CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk, CK_44XX), + CLK(NULL, "usb_host_hs_utmi_p2_clk", &usb_host_hs_utmi_p2_clk, CK_44XX), + CLK(NULL, "usb_host_hs_utmi_p3_clk", &usb_host_hs_utmi_p3_clk, CK_44XX), + CLK(NULL, "usb_host_hs_hsic480m_p1_clk", &usb_host_hs_hsic480m_p1_clk, CK_44XX), + CLK(NULL, "usb_host_hs_hsic60m_p1_clk", &usb_host_hs_hsic60m_p1_clk, CK_44XX), + CLK(NULL, "usb_host_hs_hsic60m_p2_clk", &usb_host_hs_hsic60m_p2_clk, CK_44XX), + CLK(NULL, "usb_host_hs_hsic480m_p2_clk", &usb_host_hs_hsic480m_p2_clk, CK_44XX), + CLK(NULL, "usb_host_hs_func48mclk", &usb_host_hs_func48mclk, CK_44XX), + CLK(NULL, "usb_host_hs_fck", &usb_host_hs_fck, CK_44XX), + CLK("usbhs_omap", "hs_fck", &usb_host_hs_fck, CK_44XX), + CLK("usbhs_omap", "usbhost_ick", &dummy_ck, CK_44XX), + CLK(NULL, "otg_60m_gfclk", &otg_60m_gfclk, CK_44XX), + CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk, CK_44XX), + CLK("musb-omap2430", "ick", &usb_otg_hs_ick, CK_44XX), + CLK(NULL, "usb_phy_cm_clk32k", &usb_phy_cm_clk32k, CK_44XX), + CLK(NULL, "usb_tll_hs_usb_ch2_clk", &usb_tll_hs_usb_ch2_clk, CK_44XX), + CLK(NULL, "usb_tll_hs_usb_ch0_clk", &usb_tll_hs_usb_ch0_clk, CK_44XX), + CLK(NULL, "usb_tll_hs_usb_ch1_clk", &usb_tll_hs_usb_ch1_clk, CK_44XX), + CLK(NULL, "usb_tll_hs_ick", &usb_tll_hs_ick, CK_44XX), + CLK("usbhs_omap", "usbtll_ick", &usb_tll_hs_ick, CK_44XX), + CLK("usbhs_omap", "usbtll_fck", &dummy_ck, CK_44XX), + CLK(NULL, "usim_ck", &usim_ck, CK_44XX), + CLK(NULL, "usim_fclk", &usim_fclk, CK_44XX), + CLK(NULL, "usim_fck", &usim_fck, CK_44XX), + CLK("omap_wdt", "fck", &wd_timer2_fck, CK_44XX), + CLK(NULL, "mailboxes_ick", &dummy_ck, CK_44XX), + CLK(NULL, "wd_timer3_fck", &wd_timer3_fck, CK_44XX), + CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck, CK_44XX), + CLK(NULL, "trace_clk_div_ck", &trace_clk_div_ck, CK_44XX), + CLK(NULL, "gpmc_ck", &dummy_ck, CK_44XX), + CLK(NULL, "gpt1_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt2_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt3_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt4_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt5_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt6_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt7_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt8_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt9_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt10_ick", &dummy_ck, CK_44XX), + CLK(NULL, "gpt11_ick", &dummy_ck, CK_44XX), + CLK("omap_i2c.1", "ick", &dummy_ck, CK_44XX), + CLK("omap_i2c.2", "ick", &dummy_ck, CK_44XX), + CLK("omap_i2c.3", "ick", &dummy_ck, CK_44XX), + CLK("omap_i2c.4", "ick", &dummy_ck, CK_44XX), + CLK("omap_hsmmc.0", "ick", &dummy_ck, CK_44XX), + CLK("omap_hsmmc.1", "ick", &dummy_ck, CK_44XX), + CLK("omap_hsmmc.2", "ick", &dummy_ck, CK_44XX), + CLK("omap_hsmmc.3", "ick", &dummy_ck, CK_44XX), + CLK("omap_hsmmc.4", "ick", &dummy_ck, CK_44XX), + CLK("omap-mcbsp.1", "ick", &dummy_ck, CK_44XX), + CLK("omap-mcbsp.2", "ick", &dummy_ck, CK_44XX), + CLK("omap-mcbsp.3", "ick", &dummy_ck, CK_44XX), + CLK("omap-mcbsp.4", "ick", &dummy_ck, CK_44XX), + CLK("omap2_mcspi.1", "ick", &dummy_ck, CK_44XX), + CLK("omap2_mcspi.2", "ick", &dummy_ck, CK_44XX), + CLK("omap2_mcspi.3", "ick", &dummy_ck, CK_44XX), + CLK("omap2_mcspi.4", "ick", &dummy_ck, CK_44XX), + CLK(NULL, "uart1_ick", &dummy_ck, CK_44XX), + CLK(NULL, "uart2_ick", &dummy_ck, CK_44XX), + CLK(NULL, "uart3_ick", &dummy_ck, CK_44XX), + CLK(NULL, "uart4_ick", &dummy_ck, CK_44XX), + CLK("omap_wdt", "ick", &dummy_ck, CK_44XX), + CLK(NULL, "auxclk0_src_ck", &auxclk0_src_ck, CK_44XX), + CLK(NULL, "auxclk0_ck", &auxclk0_ck, CK_44XX), + CLK(NULL, "auxclk1_src_ck", &auxclk1_src_ck, CK_44XX), + CLK(NULL, "auxclk1_ck", &auxclk1_ck, CK_44XX), + CLK(NULL, "auxclk2_src_ck", &auxclk2_src_ck, CK_44XX), + CLK(NULL, "auxclk2_ck", &auxclk2_ck, CK_44XX), + CLK(NULL, "auxclk3_src_ck", &auxclk3_src_ck, CK_44XX), + CLK(NULL, "auxclk3_ck", &auxclk3_ck, CK_44XX), + CLK(NULL, "auxclk4_src_ck", &auxclk4_src_ck, CK_44XX), + CLK(NULL, "auxclk4_ck", &auxclk4_ck, CK_44XX), + CLK(NULL, "auxclk5_src_ck", &auxclk5_src_ck, CK_44XX), + CLK(NULL, "auxclk5_ck", &auxclk5_ck, CK_44XX), + CLK(NULL, "auxclkreq0_ck", &auxclkreq0_ck, CK_44XX), + CLK(NULL, "auxclkreq1_ck", &auxclkreq1_ck, CK_44XX), + CLK(NULL, "auxclkreq2_ck", &auxclkreq2_ck, CK_44XX), + CLK(NULL, "auxclkreq3_ck", &auxclkreq3_ck, CK_44XX), + CLK(NULL, "auxclkreq4_ck", &auxclkreq4_ck, CK_44XX), + CLK(NULL, "auxclkreq5_ck", &auxclkreq5_ck, CK_44XX), + CLK("smp_twd", NULL, &smp_twd_443x, CK_443X), + CLK("smp_twd", NULL, &smp_twd_446x, CK_446X), + CLK("omap_timer.1", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.2", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.3", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.4", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.5", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.6", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.7", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.8", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.9", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.10", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.11", "32k_ck", &sys_32k_ck, CK_44XX), + CLK("omap_timer.1", "sys_ck", &sys_clkin_ck, CK_44XX), + CLK("omap_timer.2", "sys_ck", &sys_clkin_ck, CK_44XX), + CLK("omap_timer.3", "sys_ck", &sys_clkin_ck, CK_44XX), + CLK("omap_timer.4", "sys_ck", &sys_clkin_ck, CK_44XX), + CLK("omap_timer.9", "sys_ck", &sys_clkin_ck, CK_44XX), + CLK("omap_timer.10", "sys_ck", &sys_clkin_ck, CK_44XX), + CLK("omap_timer.11", "sys_ck", &sys_clkin_ck, CK_44XX), + CLK("omap_timer.5", "sys_ck", &syc_clk_div_ck, CK_44XX), + CLK("omap_timer.6", "sys_ck", &syc_clk_div_ck, CK_44XX), + CLK("omap_timer.7", "sys_ck", &syc_clk_div_ck, CK_44XX), + CLK("omap_timer.8", "sys_ck", &syc_clk_div_ck, CK_44XX), +}; + +#define L3_OPP50_RATE 100000000 +#define DPLL_CORE_M2_OPP50_RATE 400000000 +#define DPLL_CORE_M2_OPP100_RATE 800000000 +#define DPLL_CORE_M3_OPP50_RATE 200000000 +#define DPLL_CORE_M3_OPP100_RATE 320000000 +#define DPLL_CORE_M6_OPP50_RATE 200000000 +#define DPLL_CORE_M6_OPP100_RATE 266600000 +#define DPLL_CORE_M7_OPP50_RATE 133333333 +#define DPLL_CORE_M7_OPP100_RATE 266666666 +#define DPLL_PER_M3_OPP50_RATE 192000000 +#define DPLL_PER_M3_OPP100_RATE 256000000 +#define DPLL_PER_M6_OPP50_RATE 192000000 +#define DPLL_PER_M6_OPP100_RATE 384000000 + +static long omap4_virt_l3_round_rate(struct clk *clk, unsigned long rate) +{ + long parent_rate; + + if (!clk || !clk->parent) + return 0; + + if (clk->parent->round_rate) { + parent_rate = clk->parent->round_rate(clk->parent, rate * 2); + if (parent_rate) + return parent_rate / 2; + } + return 0; +} + +static unsigned long omap4_virt_l3_recalc(struct clk *clk) +{ + if (!clk || !clk->parent) + return 0; + + return clk->parent->rate / 2; +} + +static int omap4_clksel_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EINVAL; + + if (!clk->set_rate || !clk->round_rate) + return ret; + + rate = clk->round_rate(clk, rate); + if (rate) { + ret = clk->set_rate(clk, rate); + if (!ret) + propagate_rate(clk); + } + return ret; +} + +struct virt_l3_ck_deps { + unsigned long core_m2_rate; + unsigned long core_m3_rate; + unsigned long core_m6_rate; + unsigned long core_m7_rate; + unsigned long per_m3_rate; + unsigned long per_m6_rate; +}; + +#define NO_OF_L3_OPPS 2 +#define L3_OPP_50_INDEX 0 +#define L3_OPP_100_INDEX 1 + +static struct virt_l3_ck_deps omap4_virt_l3_clk_deps[NO_OF_L3_OPPS] = { + { /* OPP 50 */ + .core_m2_rate = DPLL_CORE_M2_OPP50_RATE, + .core_m3_rate = DPLL_CORE_M3_OPP50_RATE, + .core_m6_rate = DPLL_CORE_M6_OPP50_RATE, + .core_m7_rate = DPLL_CORE_M7_OPP50_RATE, + .per_m3_rate = DPLL_PER_M3_OPP50_RATE, + .per_m6_rate = DPLL_PER_M6_OPP50_RATE, + }, + { /* OPP 100 */ + .core_m2_rate = DPLL_CORE_M2_OPP100_RATE, + .core_m3_rate = DPLL_CORE_M3_OPP100_RATE, + .core_m6_rate = DPLL_CORE_M6_OPP100_RATE, + .core_m7_rate = DPLL_CORE_M7_OPP100_RATE, + .per_m3_rate = DPLL_PER_M3_OPP100_RATE, + .per_m6_rate = DPLL_PER_M6_OPP100_RATE, + }, +}; + +static int omap4_virt_l3_set_rate(struct clk *clk, unsigned long rate) +{ + struct virt_l3_ck_deps *l3_deps; + + if (rate <= L3_OPP50_RATE) + l3_deps = &omap4_virt_l3_clk_deps[L3_OPP_50_INDEX]; + else + l3_deps = &omap4_virt_l3_clk_deps[L3_OPP_100_INDEX]; + + omap4_clksel_set_rate(&dpll_core_m3x2_ck, l3_deps->core_m3_rate); + omap4_clksel_set_rate(&dpll_core_m6x2_ck, l3_deps->core_m6_rate); + omap4_clksel_set_rate(&dpll_core_m7x2_ck, l3_deps->core_m7_rate); + omap4_clksel_set_rate(&dpll_per_m3x2_ck, l3_deps->per_m3_rate); + omap4_clksel_set_rate(&dpll_per_m6x2_ck, l3_deps->per_m6_rate); + omap4_clksel_set_rate(&dpll_core_m5x2_ck, rate * 2); + omap4_clksel_set_rate(&dpll_core_m2_ck, l3_deps->core_m2_rate); + + clk->rate = rate; + return 0; +} int __init omap4xxx_clk_init(void) { struct omap_clk *c; - u32 cpu_clkflg; + u32 cpu_clkflg = 0; - if (cpu_is_omap44xx()) { - cpu_mask = RATE_IN_4430; + if (cpu_is_omap443x()) { + cpu_mask = RATE_IN_443X; cpu_clkflg = CK_443X; + } else if (cpu_is_omap446x()) { + cpu_mask = RATE_IN_446X; + cpu_clkflg = CK_446X; } clk_init(&omap2_clk_functions); diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 6cb6c03..583cc3d 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -718,6 +718,8 @@ int clkdm_sleep(struct clockdomain *clkdm) */ int clkdm_wakeup(struct clockdomain *clkdm) { + int ret; + if (!clkdm) return -EINVAL; @@ -732,7 +734,10 @@ int clkdm_wakeup(struct clockdomain *clkdm) pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); - return arch_clkdm->clkdm_wakeup(clkdm); + ret = arch_clkdm->clkdm_wakeup(clkdm); + ret |= pwrdm_wait_transition(clkdm->pwrdm.ptr); + + return ret; } /** @@ -795,6 +800,27 @@ void clkdm_deny_idle(struct clockdomain *clkdm) arch_clkdm->clkdm_deny_idle(clkdm); } +/** + * clkdm_is_idle - Check if the clkdm hwsup/autoidle is enabled + * @clkdm: struct clockdomain * + * + * Returns true if the clockdomain is in hardware-supervised + * idle mode, or 0 otherwise. + * + */ +int clkdm_is_idle(struct clockdomain *clkdm) +{ + if (!clkdm) + return -EINVAL; + + if (!arch_clkdm || !arch_clkdm->clkdm_is_idle) + return -EINVAL; + + pr_debug("clockdomain: reading idle state for %s\n", clkdm->name); + + return arch_clkdm->clkdm_is_idle(clkdm); +} + /* Clockdomain-to-clock framework interface code */ @@ -825,7 +851,12 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) if (!arch_clkdm || !arch_clkdm->clkdm_clk_enable) return -EINVAL; - if (atomic_inc_return(&clkdm->usecount) > 1) + /* + * For arch's with no autodeps, clkcm_clk_enable + * should be called for every clock instance that is + * enabled, so the clkdm can be force woken up. + */ + if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) return 0; /* Clockdomain now has one enabled downstream clock */ diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index 5823584..085ed82 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h @@ -138,6 +138,7 @@ struct clockdomain { * @clkdm_wakeup: Force a clockdomain to wakeup * @clkdm_allow_idle: Enable hw supervised idle transitions for clock domain * @clkdm_deny_idle: Disable hw supervised idle transitions for clock domain + * @clkdm_is_idle: Check if hw supervised idle transitions are enabled * @clkdm_clk_enable: Put the clkdm in right state for a clock enable * @clkdm_clk_disable: Put the clkdm in right state for a clock disable */ @@ -154,6 +155,7 @@ struct clkdm_ops { int (*clkdm_wakeup)(struct clockdomain *clkdm); void (*clkdm_allow_idle)(struct clockdomain *clkdm); void (*clkdm_deny_idle)(struct clockdomain *clkdm); + int (*clkdm_is_idle)(struct clockdomain *clkdm); int (*clkdm_clk_enable)(struct clockdomain *clkdm); int (*clkdm_clk_disable)(struct clockdomain *clkdm); }; @@ -177,6 +179,7 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); void clkdm_allow_idle(struct clockdomain *clkdm); void clkdm_deny_idle(struct clockdomain *clkdm); +int clkdm_is_idle(struct clockdomain *clkdm); int clkdm_wakeup(struct clockdomain *clkdm); int clkdm_sleep(struct clockdomain *clkdm); diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c index 48d0db7..db49baa 100644 --- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c +++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c @@ -13,6 +13,7 @@ */ #include <linux/types.h> +#include <linux/errno.h> #include <plat/prcm.h> #include "prm.h" #include "prm2xxx_3xxx.h" @@ -146,6 +147,15 @@ static void omap2_clkdm_deny_idle(struct clockdomain *clkdm) _clkdm_del_autodeps(clkdm); } +static int omap2_clkdm_is_idle(struct clockdomain *clkdm) +{ + if (!clkdm->clktrctrl_mask) + return -1; + + return omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); +} + static void _enable_hwsup(struct clockdomain *clkdm) { if (cpu_is_omap24xx()) @@ -252,6 +262,7 @@ struct clkdm_ops omap2_clkdm_operations = { .clkdm_wakeup = omap2_clkdm_wakeup, .clkdm_allow_idle = omap2_clkdm_allow_idle, .clkdm_deny_idle = omap2_clkdm_deny_idle, + .clkdm_is_idle = omap2_clkdm_is_idle, .clkdm_clk_enable = omap2_clkdm_clk_enable, .clkdm_clk_disable = omap2_clkdm_clk_disable, }; @@ -269,6 +280,7 @@ struct clkdm_ops omap3_clkdm_operations = { .clkdm_wakeup = omap3_clkdm_wakeup, .clkdm_allow_idle = omap3_clkdm_allow_idle, .clkdm_deny_idle = omap3_clkdm_deny_idle, + .clkdm_is_idle = omap2_clkdm_is_idle, .clkdm_clk_enable = omap2_clkdm_clk_enable, .clkdm_clk_disable = omap2_clkdm_clk_disable, }; diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c index a1a4ecd..5024e63 100644 --- a/arch/arm/mach-omap2/clockdomain44xx.c +++ b/arch/arm/mach-omap2/clockdomain44xx.c @@ -93,15 +93,16 @@ static void omap4_clkdm_deny_idle(struct clockdomain *clkdm) clkdm->cm_inst, clkdm->clkdm_offs); } -static int omap4_clkdm_clk_enable(struct clockdomain *clkdm) +static int omap4_clkdm_is_idle(struct clockdomain *clkdm) { - bool hwsup = false; - - hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition, - clkdm->cm_inst, clkdm->clkdm_offs); + return omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition, + clkdm->cm_inst, clkdm->clkdm_offs); +} - if (!hwsup) - clkdm_wakeup(clkdm); +static int omap4_clkdm_clk_enable(struct clockdomain *clkdm) +{ + /* For every clock enable, force wakeup the clkdm */ + clkdm_wakeup(clkdm); return 0; } @@ -132,6 +133,7 @@ struct clkdm_ops omap4_clkdm_operations = { .clkdm_wakeup = omap4_clkdm_wakeup, .clkdm_allow_idle = omap4_clkdm_allow_idle, .clkdm_deny_idle = omap4_clkdm_deny_idle, + .clkdm_is_idle = omap4_clkdm_is_idle, .clkdm_clk_enable = omap4_clkdm_clk_enable, .clkdm_clk_disable = omap4_clkdm_clk_disable, }; diff --git a/arch/arm/mach-omap2/clockdomains44xx_data.c b/arch/arm/mach-omap2/clockdomains44xx_data.c index a607ec1..8c73442 100644 --- a/arch/arm/mach-omap2/clockdomains44xx_data.c +++ b/arch/arm/mach-omap2/clockdomains44xx_data.c @@ -35,55 +35,55 @@ static struct clkdm_dep ducati_wkup_sleep_deps[] = { { .clkdm_name = "abe_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_2_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_dss_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_gfx_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_init_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_cfg_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_per_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_secure_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_wkup_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "tesla_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -91,15 +91,15 @@ static struct clkdm_dep ducati_wkup_sleep_deps[] = { static struct clkdm_dep iss_wkup_sleep_deps[] = { { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -107,11 +107,11 @@ static struct clkdm_dep iss_wkup_sleep_deps[] = { static struct clkdm_dep ivahd_wkup_sleep_deps[] = { { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -119,35 +119,35 @@ static struct clkdm_dep ivahd_wkup_sleep_deps[] = { static struct clkdm_dep l3_d2d_wkup_sleep_deps[] = { { .clkdm_name = "abe_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_2_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_init_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_cfg_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_per_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -155,47 +155,47 @@ static struct clkdm_dep l3_d2d_wkup_sleep_deps[] = { static struct clkdm_dep l3_dma_wkup_sleep_deps[] = { { .clkdm_name = "abe_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "ducati_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_dss_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_init_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_cfg_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_per_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_secure_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_wkup_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -203,15 +203,15 @@ static struct clkdm_dep l3_dma_wkup_sleep_deps[] = { static struct clkdm_dep l3_dss_wkup_sleep_deps[] = { { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_2_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -219,15 +219,15 @@ static struct clkdm_dep l3_dss_wkup_sleep_deps[] = { static struct clkdm_dep l3_gfx_wkup_sleep_deps[] = { { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -235,31 +235,31 @@ static struct clkdm_dep l3_gfx_wkup_sleep_deps[] = { static struct clkdm_dep l3_init_wkup_sleep_deps[] = { { .clkdm_name = "abe_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_cfg_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_per_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_secure_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_wkup_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -267,15 +267,15 @@ static struct clkdm_dep l3_init_wkup_sleep_deps[] = { static struct clkdm_dep l4_secure_wkup_sleep_deps[] = { { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_per_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -283,59 +283,59 @@ static struct clkdm_dep l4_secure_wkup_sleep_deps[] = { static struct clkdm_dep mpuss_wkup_sleep_deps[] = { { .clkdm_name = "abe_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "ducati_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_2_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_dss_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_gfx_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_init_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_cfg_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_per_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_secure_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_wkup_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "tesla_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -343,39 +343,39 @@ static struct clkdm_dep mpuss_wkup_sleep_deps[] = { static struct clkdm_dep tesla_wkup_sleep_deps[] = { { .clkdm_name = "abe_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "ivahd_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_1_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_2_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_emif_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l3_init_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_cfg_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_per_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { .clkdm_name = "l4_wkup_clkdm", - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430) + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX) }, { NULL }, }; @@ -387,7 +387,7 @@ static struct clockdomain l4_cefuse_44xx_clkdm = { .cm_inst = OMAP4430_CM2_CEFUSE_INST, .clkdm_offs = OMAP4430_CM2_CEFUSE_CEFUSE_CDOFFS, .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l4_cfg_44xx_clkdm = { @@ -398,7 +398,7 @@ static struct clockdomain l4_cfg_44xx_clkdm = { .clkdm_offs = OMAP4430_CM2_CORE_L4CFG_CDOFFS, .dep_bit = OMAP4430_L4CFG_STATDEP_SHIFT, .flags = CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain tesla_44xx_clkdm = { @@ -411,7 +411,7 @@ static struct clockdomain tesla_44xx_clkdm = { .wkdep_srcs = tesla_wkup_sleep_deps, .sleepdep_srcs = tesla_wkup_sleep_deps, .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_gfx_44xx_clkdm = { @@ -424,7 +424,7 @@ static struct clockdomain l3_gfx_44xx_clkdm = { .wkdep_srcs = l3_gfx_wkup_sleep_deps, .sleepdep_srcs = l3_gfx_wkup_sleep_deps, .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain ivahd_44xx_clkdm = { @@ -437,7 +437,7 @@ static struct clockdomain ivahd_44xx_clkdm = { .wkdep_srcs = ivahd_wkup_sleep_deps, .sleepdep_srcs = ivahd_wkup_sleep_deps, .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l4_secure_44xx_clkdm = { @@ -450,7 +450,7 @@ static struct clockdomain l4_secure_44xx_clkdm = { .wkdep_srcs = l4_secure_wkup_sleep_deps, .sleepdep_srcs = l4_secure_wkup_sleep_deps, .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l4_per_44xx_clkdm = { @@ -461,7 +461,7 @@ static struct clockdomain l4_per_44xx_clkdm = { .clkdm_offs = OMAP4430_CM2_L4PER_L4PER_CDOFFS, .dep_bit = OMAP4430_L4PER_STATDEP_SHIFT, .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain abe_44xx_clkdm = { @@ -472,7 +472,7 @@ static struct clockdomain abe_44xx_clkdm = { .clkdm_offs = OMAP4430_CM1_ABE_ABE_CDOFFS, .dep_bit = OMAP4430_ABE_STATDEP_SHIFT, .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_instr_44xx_clkdm = { @@ -481,7 +481,7 @@ static struct clockdomain l3_instr_44xx_clkdm = { .prcm_partition = OMAP4430_CM2_PARTITION, .cm_inst = OMAP4430_CM2_CORE_INST, .clkdm_offs = OMAP4430_CM2_CORE_L3INSTR_CDOFFS, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_init_44xx_clkdm = { @@ -493,8 +493,8 @@ static struct clockdomain l3_init_44xx_clkdm = { .dep_bit = OMAP4430_L3INIT_STATDEP_SHIFT, .wkdep_srcs = l3_init_wkup_sleep_deps, .sleepdep_srcs = l3_init_wkup_sleep_deps, - .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .flags = CLKDM_CAN_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain mpuss_44xx_clkdm = { @@ -506,7 +506,7 @@ static struct clockdomain mpuss_44xx_clkdm = { .wkdep_srcs = mpuss_wkup_sleep_deps, .sleepdep_srcs = mpuss_wkup_sleep_deps, .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain mpu0_44xx_clkdm = { @@ -516,7 +516,7 @@ static struct clockdomain mpu0_44xx_clkdm = { .cm_inst = OMAP4430_PRCM_MPU_CPU0_INST, .clkdm_offs = OMAP4430_PRCM_MPU_CPU0_CPU0_CDOFFS, .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain mpu1_44xx_clkdm = { @@ -526,7 +526,7 @@ static struct clockdomain mpu1_44xx_clkdm = { .cm_inst = OMAP4430_PRCM_MPU_CPU1_INST, .clkdm_offs = OMAP4430_PRCM_MPU_CPU1_CPU1_CDOFFS, .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_emif_44xx_clkdm = { @@ -537,7 +537,7 @@ static struct clockdomain l3_emif_44xx_clkdm = { .clkdm_offs = OMAP4430_CM2_CORE_MEMIF_CDOFFS, .dep_bit = OMAP4430_MEMIF_STATDEP_SHIFT, .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l4_ao_44xx_clkdm = { @@ -547,7 +547,7 @@ static struct clockdomain l4_ao_44xx_clkdm = { .cm_inst = OMAP4430_CM2_ALWAYS_ON_INST, .clkdm_offs = OMAP4430_CM2_ALWAYS_ON_ALWON_CDOFFS, .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain ducati_44xx_clkdm = { @@ -560,7 +560,7 @@ static struct clockdomain ducati_44xx_clkdm = { .wkdep_srcs = ducati_wkup_sleep_deps, .sleepdep_srcs = ducati_wkup_sleep_deps, .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_2_44xx_clkdm = { @@ -571,7 +571,7 @@ static struct clockdomain l3_2_44xx_clkdm = { .clkdm_offs = OMAP4430_CM2_CORE_L3_2_CDOFFS, .dep_bit = OMAP4430_L3_2_STATDEP_SHIFT, .flags = CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_1_44xx_clkdm = { @@ -582,7 +582,7 @@ static struct clockdomain l3_1_44xx_clkdm = { .clkdm_offs = OMAP4430_CM2_CORE_L3_1_CDOFFS, .dep_bit = OMAP4430_L3_1_STATDEP_SHIFT, .flags = CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_d2d_44xx_clkdm = { @@ -594,7 +594,7 @@ static struct clockdomain l3_d2d_44xx_clkdm = { .wkdep_srcs = l3_d2d_wkup_sleep_deps, .sleepdep_srcs = l3_d2d_wkup_sleep_deps, .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain iss_44xx_clkdm = { @@ -605,8 +605,8 @@ static struct clockdomain iss_44xx_clkdm = { .clkdm_offs = OMAP4430_CM2_CAM_CAM_CDOFFS, .wkdep_srcs = iss_wkup_sleep_deps, .sleepdep_srcs = iss_wkup_sleep_deps, - .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .flags = CLKDM_CAN_SWSUP, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_dss_44xx_clkdm = { @@ -619,7 +619,7 @@ static struct clockdomain l3_dss_44xx_clkdm = { .wkdep_srcs = l3_dss_wkup_sleep_deps, .sleepdep_srcs = l3_dss_wkup_sleep_deps, .flags = CLKDM_CAN_HWSUP_SWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l4_wkup_44xx_clkdm = { @@ -630,7 +630,7 @@ static struct clockdomain l4_wkup_44xx_clkdm = { .clkdm_offs = OMAP4430_PRM_WKUP_CM_WKUP_CDOFFS, .dep_bit = OMAP4430_L4WKUP_STATDEP_SHIFT, .flags = CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain emu_sys_44xx_clkdm = { @@ -640,7 +640,7 @@ static struct clockdomain emu_sys_44xx_clkdm = { .cm_inst = OMAP4430_PRM_EMU_CM_INST, .clkdm_offs = OMAP4430_PRM_EMU_CM_EMU_CDOFFS, .flags = CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain l3_dma_44xx_clkdm = { @@ -652,7 +652,7 @@ static struct clockdomain l3_dma_44xx_clkdm = { .wkdep_srcs = l3_dma_wkup_sleep_deps, .sleepdep_srcs = l3_dma_wkup_sleep_deps, .flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct clockdomain *clockdomains_omap44xx[] __initdata = { diff --git a/arch/arm/mach-omap2/cm-regbits-44xx.h b/arch/arm/mach-omap2/cm-regbits-44xx.h index 9d47a05..4c4cbfa 100644 --- a/arch/arm/mach-omap2/cm-regbits-44xx.h +++ b/arch/arm/mach-omap2/cm-regbits-44xx.h @@ -106,6 +106,10 @@ #define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK (1 << 9) +/* Used by CM_L4CFG_CLKSTCTRL */ +#define OMAP4460_CLKACTIVITY_CORE_TS_GFCLK_SHIFT 9 +#define OMAP4460_CLKACTIVITY_CORE_TS_GFCLK_MASK (1 << 9) + /* Used by CM_CEFUSE_CLKSTCTRL */ #define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_SHIFT 9 #define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK (1 << 9) @@ -418,6 +422,10 @@ #define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_SHIFT 11 #define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK (1 << 11) +/* Used by CM_WKUP_CLKSTCTRL */ +#define OMAP4460_CLKACTIVITY_WKUP_TS_GFCLK_SHIFT 13 +#define OMAP4460_CLKACTIVITY_WKUP_TS_GFCLK_MASK (1 << 13) + /* * Used by CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, * CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, @@ -449,6 +457,10 @@ #define OMAP4430_CLKSEL_60M_SHIFT 24 #define OMAP4430_CLKSEL_60M_MASK (1 << 24) +/* Used by CM_MPU_MPU_CLKCTRL */ +#define OMAP4460_CLKSEL_ABE_DIV_MODE_SHIFT 25 +#define OMAP4460_CLKSEL_ABE_DIV_MODE_MASK (1 << 25) + /* Used by CM1_ABE_AESS_CLKCTRL */ #define OMAP4430_CLKSEL_AESS_FCLK_SHIFT 24 #define OMAP4430_CLKSEL_AESS_FCLK_MASK (1 << 24) @@ -468,6 +480,10 @@ #define OMAP4430_CLKSEL_DIV_SHIFT 24 #define OMAP4430_CLKSEL_DIV_MASK (1 << 24) +/* Used by CM_MPU_MPU_CLKCTRL */ +#define OMAP4460_CLKSEL_EMIF_DIV_MODE_SHIFT 24 +#define OMAP4460_CLKSEL_EMIF_DIV_MODE_MASK (1 << 24) + /* Used by CM_CAM_FDIF_CLKCTRL */ #define OMAP4430_CLKSEL_FCLK_SHIFT 24 #define OMAP4430_CLKSEL_FCLK_MASK (0x3 << 24) @@ -572,6 +588,14 @@ #define OMAP4430_D2D_STATDEP_SHIFT 18 #define OMAP4430_D2D_STATDEP_MASK (1 << 18) +/* Used by CM_CLKSEL_DPLL_MPU */ +#define OMAP4460_DCC_COUNT_MAX_SHIFT 24 +#define OMAP4460_DCC_COUNT_MAX_MASK (0xff << 24) + +/* Used by CM_CLKSEL_DPLL_MPU */ +#define OMAP4460_DCC_EN_SHIFT 22 +#define OMAP4460_DCC_EN_MASK (1 << 22) + /* * Used by CM_SSC_DELTAMSTEP_DPLL_ABE, CM_SSC_DELTAMSTEP_DPLL_CORE, * CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE, CM_SSC_DELTAMSTEP_DPLL_DDRPHY, @@ -1204,6 +1228,10 @@ #define OMAP4430_MODULEMODE_SHIFT 0 #define OMAP4430_MODULEMODE_MASK (0x3 << 0) +/* Used by CM_L4CFG_DYNAMICDEP */ +#define OMAP4460_MPU_DYNDEP_SHIFT 19 +#define OMAP4460_MPU_DYNDEP_MASK (1 << 19) + /* Used by CM_DSS_DSS_CLKCTRL */ #define OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT 9 #define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK (1 << 9) @@ -1298,6 +1326,10 @@ #define OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT 10 #define OMAP4430_OPTFCLKEN_SYS_CLK_MASK (1 << 10) +/* Used by CM_WKUP_BANDGAP_CLKCTRL */ +#define OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT 8 +#define OMAP4460_OPTFCLKEN_TS_FCLK_MASK (1 << 8) + /* Used by CM_DSS_DSS_CLKCTRL */ #define OMAP4430_OPTFCLKEN_TV_CLK_SHIFT 11 #define OMAP4430_OPTFCLKEN_TV_CLK_MASK (1 << 11) diff --git a/arch/arm/mach-omap2/cm1_44xx.h b/arch/arm/mach-omap2/cm1_44xx.h index e2d7a56..6a34bed 100644 --- a/arch/arm/mach-omap2/cm1_44xx.h +++ b/arch/arm/mach-omap2/cm1_44xx.h @@ -82,8 +82,8 @@ #define OMAP4430_CM_DIV_M7_DPLL_CORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0044) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_CORE_OFFSET 0x0048 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_CORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0048) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_CORE_OFFSET 0x004c -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_CORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x004c) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_CORE_OFFSET 0x004c +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_CORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x004c) #define OMAP4_CM_EMU_OVERRIDE_DPLL_CORE_OFFSET 0x0050 #define OMAP4430_CM_EMU_OVERRIDE_DPLL_CORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0050) #define OMAP4_CM_CLKMODE_DPLL_MPU_OFFSET 0x0060 @@ -98,8 +98,8 @@ #define OMAP4430_CM_DIV_M2_DPLL_MPU OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0070) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_MPU_OFFSET 0x0088 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_MPU OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0088) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_MPU_OFFSET 0x008c -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_MPU OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x008c) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_MPU_OFFSET 0x008c +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_MPU OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x008c) #define OMAP4_CM_BYPCLK_DPLL_MPU_OFFSET 0x009c #define OMAP4430_CM_BYPCLK_DPLL_MPU OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x009c) #define OMAP4_CM_CLKMODE_DPLL_IVA_OFFSET 0x00a0 @@ -116,8 +116,8 @@ #define OMAP4430_CM_DIV_M5_DPLL_IVA OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x00bc) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_IVA_OFFSET 0x00c8 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_IVA OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x00c8) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_IVA_OFFSET 0x00cc -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_IVA OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x00cc) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_IVA_OFFSET 0x00cc +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_IVA OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x00cc) #define OMAP4_CM_BYPCLK_DPLL_IVA_OFFSET 0x00dc #define OMAP4430_CM_BYPCLK_DPLL_IVA OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x00dc) #define OMAP4_CM_CLKMODE_DPLL_ABE_OFFSET 0x00e0 @@ -134,8 +134,8 @@ #define OMAP4430_CM_DIV_M3_DPLL_ABE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x00f4) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_ABE_OFFSET 0x0108 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_ABE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0108) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_ABE_OFFSET 0x010c -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_ABE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x010c) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_ABE_OFFSET 0x010c +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_ABE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x010c) #define OMAP4_CM_CLKMODE_DPLL_DDRPHY_OFFSET 0x0120 #define OMAP4430_CM_CLKMODE_DPLL_DDRPHY OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0120) #define OMAP4_CM_IDLEST_DPLL_DDRPHY_OFFSET 0x0124 @@ -154,8 +154,8 @@ #define OMAP4430_CM_DIV_M6_DPLL_DDRPHY OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0140) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_DDRPHY_OFFSET 0x0148 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_DDRPHY OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0148) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_DDRPHY_OFFSET 0x014c -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_DDRPHY OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x014c) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_DDRPHY_OFFSET 0x014c +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_DDRPHY OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x014c) #define OMAP4_CM_SHADOW_FREQ_CONFIG1_OFFSET 0x0160 #define OMAP4430_CM_SHADOW_FREQ_CONFIG1 OMAP44XX_CM1_REGADDR(OMAP4430_CM1_CKGEN_INST, 0x0160) #define OMAP4_CM_SHADOW_FREQ_CONFIG2_OFFSET 0x0164 @@ -236,8 +236,8 @@ #define OMAP4430_CM_CLKSEL_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_INST, 0x001c) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE_OFFSET 0x0020 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_INST, 0x0020) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_CORE_RESTORE_OFFSET 0x0024 -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_INST, 0x0024) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE_OFFSET 0x0024 +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_INST, 0x0024) #define OMAP4_CM_CLKMODE_DPLL_CORE_RESTORE_OFFSET 0x0028 #define OMAP4430_CM_CLKMODE_DPLL_CORE_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_INST, 0x0028) #define OMAP4_CM_SHADOW_FREQ_CONFIG2_RESTORE_OFFSET 0x002c @@ -253,9 +253,11 @@ #define OMAP4_CM_DYN_DEP_PRESCAL_RESTORE_OFFSET 0x0040 #define OMAP4430_CM_DYN_DEP_PRESCAL_RESTORE OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_INST, 0x0040) +#ifndef __ASSEMBLER__ /* Function prototypes */ extern u32 omap4_cm1_read_inst_reg(s16 inst, u16 idx); extern void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 idx); extern u32 omap4_cm1_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); +#endif #endif diff --git a/arch/arm/mach-omap2/cm2_44xx.h b/arch/arm/mach-omap2/cm2_44xx.h index aa47450..b6ed984 100644 --- a/arch/arm/mach-omap2/cm2_44xx.h +++ b/arch/arm/mach-omap2/cm2_44xx.h @@ -121,8 +121,8 @@ #define OMAP4430_CM_DIV_M7_DPLL_PER OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x0064) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_PER_OFFSET 0x0068 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_PER OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x0068) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_PER_OFFSET 0x006c -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_PER OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x006c) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_PER_OFFSET 0x006c +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_PER OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x006c) #define OMAP4_CM_CLKMODE_DPLL_USB_OFFSET 0x0080 #define OMAP4430_CM_CLKMODE_DPLL_USB OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x0080) #define OMAP4_CM_IDLEST_DPLL_USB_OFFSET 0x0084 @@ -135,8 +135,8 @@ #define OMAP4430_CM_DIV_M2_DPLL_USB OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x0090) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_USB_OFFSET 0x00a8 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_USB OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x00a8) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_USB_OFFSET 0x00ac -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_USB OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x00ac) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_USB_OFFSET 0x00ac +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_USB OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x00ac) #define OMAP4_CM_CLKDCOLDO_DPLL_USB_OFFSET 0x00b4 #define OMAP4430_CM_CLKDCOLDO_DPLL_USB OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x00b4) #define OMAP4_CM_CLKMODE_DPLL_UNIPRO_OFFSET 0x00c0 @@ -151,8 +151,8 @@ #define OMAP4430_CM_DIV_M2_DPLL_UNIPRO OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x00d0) #define OMAP4_CM_SSC_DELTAMSTEP_DPLL_UNIPRO_OFFSET 0x00e8 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_UNIPRO OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x00e8) -#define OMAP4_CM_SSC_INSTFREQDIV_DPLL_UNIPRO_OFFSET 0x00ec -#define OMAP4430_CM_SSC_INSTFREQDIV_DPLL_UNIPRO OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x00ec) +#define OMAP4_CM_SSC_MODFREQDIV_DPLL_UNIPRO_OFFSET 0x00ec +#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_UNIPRO OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_INST, 0x00ec) /* CM2.ALWAYS_ON_CM2 register offsets */ #define OMAP4_CM_ALWON_CLKSTCTRL_OFFSET 0x0000 @@ -500,9 +500,11 @@ #define OMAP4_CM_SDMA_STATICDEP_RESTORE_OFFSET 0x005c #define OMAP4430_CM_SDMA_STATICDEP_RESTORE OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_INST, 0x005c) +#ifndef __ASSEMBLER__ /* Function prototypes */ extern u32 omap4_cm2_read_inst_reg(s16 inst, u16 idx); extern void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 idx); extern u32 omap4_cm2_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); +#endif #endif diff --git a/arch/arm/mach-omap2/cm44xx.c b/arch/arm/mach-omap2/cm44xx.c index e96f53e..16d5f3d 100644 --- a/arch/arm/mach-omap2/cm44xx.c +++ b/arch/arm/mach-omap2/cm44xx.c @@ -21,8 +21,11 @@ #include <plat/common.h> #include "cm.h" +#include "cm44xx.h" #include "cm1_44xx.h" #include "cm2_44xx.h" +#include "cminst44xx.h" +#include "prcm44xx.h" #include "cm-regbits-44xx.h" /* CM1 hardware module low-level functions */ @@ -50,3 +53,322 @@ void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) { __raw_writel(val, OMAP44XX_CM2_REGADDR(inst, reg)); } + +#define MAX_CM_REGISTERS 51 + +struct omap4_cm_tuple { + u16 addr; + u32 val; +}; + +struct omap4_cm_regs { + u32 mod_off; + u32 no_reg; + struct omap4_cm_tuple reg[MAX_CM_REGISTERS]; +}; + +static struct omap4_cm_regs cm1_regs[] = { + /* OMAP4430_CM1_OCP_SOCKET_MOD */ + { .mod_off = OMAP4430_CM1_OCP_SOCKET_INST, .no_reg = 1, + {{.addr = OMAP4_CM_CM1_PROFILING_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM1_CKGEN_MOD */ + { .mod_off = OMAP4430_CM1_CKGEN_INST, .no_reg = 4, + {{.addr = OMAP4_CM_CLKSEL_CORE_OFFSET}, + {.addr = OMAP4_CM_CLKSEL_ABE_OFFSET}, + {.addr = OMAP4_CM_DLL_CTRL_OFFSET}, + {.addr = OMAP4_CM_DYN_DEP_PRESCAL_OFFSET} }, + }, + /* OMAP4430_CM1_MPU_MOD */ + { .mod_off = OMAP4430_CM1_MPU_INST, .no_reg = 4, + {{.addr = OMAP4_CM_MPU_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_MPU_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_MPU_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_MPU_MPU_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM1_TESLA_MOD */ + { .mod_off = OMAP4430_CM1_TESLA_INST, .no_reg = 4, + {{.addr = OMAP4_CM_TESLA_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_TESLA_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_TESLA_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_TESLA_TESLA_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM1_ABE_MOD */ + { .mod_off = OMAP4430_CM1_ABE_INST, .no_reg = 15, + {{.addr = OMAP4_CM1_ABE_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_L4ABE_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_AESS_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_SLIMBUS_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET} }, + }, +}; + +static struct omap4_cm_regs cm2_regs[] = { + /* OMAP4430_CM2_OCP_SOCKET_MOD */ + {.mod_off = OMAP4430_CM2_OCP_SOCKET_INST, .no_reg = 1, + {{.addr = OMAP4_CM_CM2_PROFILING_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_CKGEN_MOD */ + {.mod_off = OMAP4430_CM2_CKGEN_INST, .no_reg = 12, + {{.addr = OMAP4_CM_CLKSEL_DUCATI_ISS_ROOT_OFFSET}, + {.addr = OMAP4_CM_CLKSEL_USB_60MHZ_OFFSET}, + {.addr = OMAP4_CM_SCALE_FCLK_OFFSET}, + {.addr = OMAP4_CM_CORE_DVFS_PERF1_OFFSET}, + {.addr = OMAP4_CM_CORE_DVFS_PERF2_OFFSET}, + {.addr = OMAP4_CM_CORE_DVFS_PERF3_OFFSET}, + {.addr = OMAP4_CM_CORE_DVFS_PERF4_OFFSET}, + {.addr = OMAP4_CM_CORE_DVFS_CURRENT_OFFSET}, + {.addr = OMAP4_CM_IVA_DVFS_PERF_TESLA_OFFSET}, + {.addr = OMAP4_CM_IVA_DVFS_PERF_IVAHD_OFFSET}, + {.addr = OMAP4_CM_IVA_DVFS_PERF_ABE_OFFSET}, + {.addr = OMAP4_CM_IVA_DVFS_CURRENT_OFFSET} }, + }, + /* OMAP4430_CM2_ALWAYS_ON_MOD */ + {.mod_off = OMAP4430_CM2_ALWAYS_ON_INST, .no_reg = 6, + {{.addr = OMAP4_CM_ALWON_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_ALWON_MDMINTC_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_ALWON_USBPHY_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_CORE_MOD */ + {.mod_off = OMAP4430_CM2_CORE_INST, .no_reg = 41, + {{.addr = OMAP4_CM_L3_1_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_L3_1_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_L3_1_L3_1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3_2_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_L3_2_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_L3_2_L3_2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3_2_GPMC_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3_2_OCMC_RAM_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_DUCATI_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_DUCATI_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_SDMA_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_SDMA_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_SDMA_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_SDMA_SDMA_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_DMM_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_EMIF_FW_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_EMIF_1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_EMIF_2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_DLL_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_EMIF_H1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_EMIF_H2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_MEMIF_DLL_H_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_D2D_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_D2D_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_D2D_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_D2D_SAD2D_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_D2D_INSTEM_ICR_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_D2D_SAD2D_FW_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4CFG_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_L4CFG_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4CFG_HW_SEM_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4CFG_SAR_ROM_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INSTR_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INSTR_L3_3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_IVAHD_MOD */ + {.mod_off = OMAP4430_CM2_IVAHD_INST, .no_reg = 5, + {{.addr = OMAP4_CM_IVAHD_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_IVAHD_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_IVAHD_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_IVAHD_SL2_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_CAM_MOD */ + {.mod_off = OMAP4430_CM2_CAM_INST, .no_reg = 5, + {{.addr = OMAP4_CM_CAM_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_CAM_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_CAM_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_CAM_FDIF_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_DSS_MOD */ + {.mod_off = OMAP4430_CM2_DSS_INST, .no_reg = 5, + {{.addr = OMAP4_CM_DSS_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_DSS_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_DSS_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_DSS_DEISS_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_GFX_MOD */ + {.mod_off = OMAP4430_CM2_GFX_INST, .no_reg = 4, + {{.addr = OMAP4_CM_GFX_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_GFX_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_GFX_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_GFX_GFX_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_L3INIT_MOD */ + {.mod_off = OMAP4430_CM2_L3INIT_INST, .no_reg = 20, + {{.addr = OMAP4_CM_L3INIT_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_L3INIT_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_HSI_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_UNIPRO1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_USB_OTG_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_P1500_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_EMAC_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_SATA_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_TPPSS_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_PCIESS_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_CCPTX_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_XHPI_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_MMC6_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_USB_HOST_FS_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_L4PER_MOD */ + {.mod_off = OMAP4430_CM2_L4PER_INST, .no_reg = 51, + {{.addr = OMAP4_CM_L4PER_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_L4PER_ADC_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_ELM_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_HECC1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_HECC2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_L4PER_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MCASP2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MCASP3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MGATE_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MSPROHG_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_SLIMBUS2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4PER_I2C5_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4SEC_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_L4SEC_STATICDEP_OFFSET}, + {.addr = OMAP4_CM_L4SEC_DYNAMICDEP_OFFSET}, + {.addr = OMAP4_CM_L4SEC_AES1_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4SEC_AES2_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4SEC_DES3DES_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4SEC_PKAEIP29_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4SEC_RNG_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4SEC_SHA2MD51_CLKCTRL_OFFSET}, + {.addr = OMAP4_CM_L4SEC_CRYPTODMA_CLKCTRL_OFFSET} }, + }, + /* OMAP4430_CM2_CEFUSE_MOD */ + {.mod_off = OMAP4430_CM2_CEFUSE_INST, .no_reg = 2, + {{.addr = OMAP4_CM_CEFUSE_CLKSTCTRL_OFFSET}, + {.addr = OMAP4_CM_CEFUSE_CEFUSE_CLKCTRL_OFFSET} }, + }, +}; + +static void omap4_cm1_prepare_off(void) +{ + u32 i, j; + struct omap4_cm_regs *cm_reg = cm1_regs; + + for (i = 0; i < ARRAY_SIZE(cm1_regs); i++, cm_reg++) { + for (j = 0; j < cm_reg->no_reg; j++) { + cm_reg->reg[j].val = + omap4_cminst_read_inst_reg(OMAP4430_CM1_PARTITION, + cm_reg->mod_off, + cm_reg->reg[j].addr); + } + } +} + +static void omap4_cm2_prepare_off(void) +{ + u32 i, j; + struct omap4_cm_regs *cm_reg = cm2_regs; + + for (i = 0; i < ARRAY_SIZE(cm2_regs); i++, cm_reg++) { + for (j = 0; j < cm_reg->no_reg; j++) { + cm_reg->reg[j].val = + omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION, + cm_reg->mod_off, + cm_reg->reg[j].addr); + } + } +} + +static void omap4_cm1_resume_off(void) +{ + u32 i, j; + struct omap4_cm_regs *cm_reg = cm1_regs; + + for (i = 0; i < ARRAY_SIZE(cm1_regs); i++, cm_reg++) { + for (j = 0; j < cm_reg->no_reg; j++) { + omap4_cminst_write_inst_reg(cm_reg->reg[j].val, + OMAP4430_CM1_PARTITION, + cm_reg->mod_off, + cm_reg->reg[j].addr); + } + } +} + +static void omap4_cm2_resume_off(void) +{ + u32 i, j; + struct omap4_cm_regs *cm_reg = cm2_regs; + + for (i = 0; i < ARRAY_SIZE(cm2_regs); i++, cm_reg++) { + for (j = 0; j < cm_reg->no_reg; j++) { + omap4_cminst_write_inst_reg(cm_reg->reg[j].val, + OMAP4430_CM2_PARTITION, + cm_reg->mod_off, + cm_reg->reg[j].addr); + } + } +} + +void omap4_cm_prepare_off(void) +{ + omap4_cm1_prepare_off(); + omap4_cm2_prepare_off(); +} + +void omap4_cm_resume_off(void) +{ + omap4_cm1_resume_off(); + omap4_cm2_resume_off(); +} diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h index 0b87ec8..4124989 100644 --- a/arch/arm/mach-omap2/cm44xx.h +++ b/arch/arm/mach-omap2/cm44xx.h @@ -27,6 +27,10 @@ # ifndef __ASSEMBLER__ extern int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg); +extern void omap4_cm_prepare_off(void); +extern void omap4_cm_resume_off(void); +extern void omap4_dpll_prepare_off(void); +extern void omap4_dpll_resume_off(void); # endif #endif diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c index 3f20cbb..4ffcb54 100644 --- a/arch/arm/mach-omap2/common.c +++ b/arch/arm/mach-omap2/common.c @@ -127,6 +127,7 @@ static struct omap_globals omap4_globals = { .tap = OMAP2_L4_IO_ADDRESS(OMAP443X_SCM_BASE), .ctrl = OMAP443X_SCM_BASE, .ctrl_pad = OMAP443X_CTRL_BASE, + .ctrl_wk_pad = OMAP443X_CTRL_WK_BASE, .prm = OMAP4430_PRM_BASE, .cm = OMAP4430_CM_BASE, .cm2 = OMAP4430_CM2_BASE, diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index da53ba3..5faf166 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -32,6 +32,7 @@ static void __iomem *omap2_ctrl_base; static void __iomem *omap4_ctrl_pad_base; +static void __iomem *omap4_ctrl_wk_pad_base; #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) struct omap3_scratchpad { @@ -146,6 +147,7 @@ static struct omap3_control_regs control_context; #define OMAP_CTRL_REGADDR(reg) (omap2_ctrl_base + (reg)) #define OMAP4_CTRL_PAD_REGADDR(reg) (omap4_ctrl_pad_base + (reg)) +#define OMAP4_CTRL_WK_PAD_REGADDR(reg) (omap4_ctrl_wk_pad_base + (reg)) void __init omap2_set_globals_control(struct omap_globals *omap2_globals) { @@ -160,6 +162,17 @@ void __init omap2_set_globals_control(struct omap_globals *omap2_globals) omap4_ctrl_pad_base = ioremap(omap2_globals->ctrl_pad, SZ_4K); WARN_ON(!omap4_ctrl_pad_base); } + + /* + * static mapping, never released. omap4 Wakeup pad is seperate + * from the core, hence need to be mapped individually. + */ + if (omap2_globals->ctrl_wk_pad) { + omap4_ctrl_wk_pad_base = ioremap(omap2_globals->ctrl_wk_pad, + SZ_4K); + WARN_ON(!omap4_ctrl_wk_pad_base); + } + } void __iomem *omap_ctrl_base_get(void) @@ -204,16 +217,66 @@ void omap_ctrl_writel(u32 val, u16 offset) * registers. This APIs will work only for OMAP4 */ +u8 omap4_ctrl_pad_readb(u16 offset) +{ + return __raw_readb(OMAP4_CTRL_PAD_REGADDR(offset)); +} + +u16 omap4_ctrl_pad_readw(u16 offset) +{ + return __raw_readw(OMAP4_CTRL_PAD_REGADDR(offset)); +} + u32 omap4_ctrl_pad_readl(u16 offset) { return __raw_readl(OMAP4_CTRL_PAD_REGADDR(offset)); } +void omap4_ctrl_pad_writeb(u8 val, u16 offset) +{ + __raw_writeb(val, OMAP4_CTRL_PAD_REGADDR(offset)); +} + +void omap4_ctrl_pad_writew(u16 val, u16 offset) +{ + __raw_writew(val, OMAP4_CTRL_PAD_REGADDR(offset)); +} + void omap4_ctrl_pad_writel(u32 val, u16 offset) { __raw_writel(val, OMAP4_CTRL_PAD_REGADDR(offset)); } +u8 omap4_ctrl_wk_pad_readb(u16 offset) +{ + return __raw_readb(OMAP4_CTRL_WK_PAD_REGADDR(offset)); +} + +u16 omap4_ctrl_wk_pad_readw(u16 offset) +{ + return __raw_readw(OMAP4_CTRL_WK_PAD_REGADDR(offset)); +} + +u32 omap4_ctrl_wk_pad_readl(u16 offset) +{ + return __raw_readl(OMAP4_CTRL_WK_PAD_REGADDR(offset)); +} + +void omap4_ctrl_wk_pad_writeb(u8 val, u16 offset) +{ + __raw_writeb(val, OMAP4_CTRL_WK_PAD_REGADDR(offset)); +} + +void omap4_ctrl_wk_pad_writew(u16 val, u16 offset) +{ + __raw_writew(val, OMAP4_CTRL_WK_PAD_REGADDR(offset)); +} + +void omap4_ctrl_wk_pad_writel(u32 val, u16 offset) +{ + __raw_writel(val, OMAP4_CTRL_WK_PAD_REGADDR(offset)); +} + #ifdef CONFIG_ARCH_OMAP3 /** diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h index a016c8b..ccebb26 100644 --- a/arch/arm/mach-omap2/control.h +++ b/arch/arm/mach-omap2/control.h @@ -195,6 +195,7 @@ #define OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO 0x249 #define OMAP44XX_CONTROL_FUSE_CORE_OPP50 0x254 #define OMAP44XX_CONTROL_FUSE_CORE_OPP100 0x257 +#define OMAP44XX_CONTROL_FUSE_CORE_OPP100OV 0x25A /* AM35XX only CONTROL_GENERAL register offsets */ #define AM35XX_CONTROL_MSUSPENDMUX_6 (OMAP2_CONTROL_GENERAL + 0x0038) @@ -378,11 +379,21 @@ extern void __iomem *omap_ctrl_base_get(void); extern u8 omap_ctrl_readb(u16 offset); extern u16 omap_ctrl_readw(u16 offset); extern u32 omap_ctrl_readl(u16 offset); +extern u8 omap4_ctrl_pad_readb(u16 offset); +extern u16 omap4_ctrl_pad_readw(u16 offset); extern u32 omap4_ctrl_pad_readl(u16 offset); +extern u8 omap4_ctrl_wk_pad_readb(u16 offset); +extern u16 omap4_ctrl_wk_pad_readw(u16 offset); +extern u32 omap4_ctrl_wk_pad_readl(u16 offset); extern void omap_ctrl_writeb(u8 val, u16 offset); extern void omap_ctrl_writew(u16 val, u16 offset); extern void omap_ctrl_writel(u32 val, u16 offset); +extern void omap4_ctrl_pad_writeb(u8 val, u16 offset); +extern void omap4_ctrl_pad_writew(u16 val, u16 offset); extern void omap4_ctrl_pad_writel(u32 val, u16 offset); +extern void omap4_ctrl_wk_pad_writeb(u8 val, u16 offset); +extern void omap4_ctrl_wk_pad_writew(u16 val, u16 offset); +extern void omap4_ctrl_wk_pad_writel(u32 val, u16 offset); extern void omap3_save_scratchpad_contents(void); extern void omap3_clear_scratchpad_contents(void); @@ -400,11 +411,21 @@ extern int omap3_ctrl_save_padconf(void); #define omap_ctrl_readb(x) 0 #define omap_ctrl_readw(x) 0 #define omap_ctrl_readl(x) 0 -#define omap4_ctrl_pad_readl(x) 0 +#define omap4_ctrl_pad_readb(x) 0 +#define omap4_ctrl_pad_readw(x) 0 +#define omap4_ctrl_pad_readl(x) 0 +#define omap4_ctrl_wk_pad_readb(x) 0 +#define omap4_ctrl_wk_pad_readw(x) 0 +#define omap4_ctrl_wk_pad_readl(x) 0 #define omap_ctrl_writeb(x, y) WARN_ON(1) #define omap_ctrl_writew(x, y) WARN_ON(1) #define omap_ctrl_writel(x, y) WARN_ON(1) +#define omap4_ctrl_pad_writeb(x, y) WARN_ON(1) +#define omap4_ctrl_pad_writew(x, y) WARN_ON(1) #define omap4_ctrl_pad_writel(x, y) WARN_ON(1) +#define omap4_ctrl_wk_pad_writeb(x, y) WARN_ON(1) +#define omap4_ctrl_wk_pad_writew(x, y) WARN_ON(1) +#define omap4_ctrl_wk_pad_writel(x, y) WARN_ON(1) #endif #endif /* __ASSEMBLY__ */ diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 4bf6e6e..da13f2d 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -30,6 +30,7 @@ #include "powerdomain.h" #include "clockdomain.h" #include <plat/serial.h> +#include <plat/omap-pm.h> #include "pm.h" #include "control.h" @@ -119,7 +120,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, } /* Execute ARM wfi */ - omap_sram_idle(); + omap_sram_idle(false); /* Re-allow idle for C1 */ if (state == &dev->states[0]) { @@ -157,7 +158,7 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, u32 mpu_deepest_state = PWRDM_POWER_RET; u32 core_deepest_state = PWRDM_POWER_RET; - if (enable_off_mode) { + if (off_mode_enabled) { mpu_deepest_state = PWRDM_POWER_OFF; /* * Erratum i583: valable for ES rev < Es1.2 on 3630. diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c new file mode 100644 index 0000000..4ddd08c --- /dev/null +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -0,0 +1,747 @@ +/* + * OMAP4 CPU idle Routines + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Rajendra Nayak <rnayak@ti.com> + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/cpuidle.h> +#include <linux/clockchips.h> +#include <linux/notifier.h> +#include <linux/cpu.h> +#include <linux/delay.h> +#include <linux/cpu_pm.h> + +#include <asm/cacheflush.h> +#include <asm/proc-fns.h> +#include <asm/hardware/gic.h> + +#include <mach/omap4-common.h> +#include <mach/omap-wakeupgen.h> + +#include <plat/gpio.h> + +#include "clockdomain.h" +#include "pm.h" +#include "prm.h" + +#ifdef CONFIG_CPU_IDLE + +/* C1 is a single-cpu C-state, it can be entered by each cpu independently */ +/* C1 - CPUx WFI + MPU ON + CORE ON */ +#define OMAP4_STATE_C1 0 +/* C2 through C4 are shared C-states, both CPUs must agree to enter */ +/* C2 - CPU0 INA + CPU1 INA + MPU INA + CORE INA */ +#define OMAP4_STATE_C2 1 +/* C3 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE CSWR */ +#define OMAP4_STATE_C3 2 +/* C4 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE OSWR */ +#define OMAP4_STATE_C4 3 + +#define OMAP4_MAX_STATES 4 + +static bool disallow_smp_idle; +module_param(disallow_smp_idle, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(disallow_smp_idle, + "Don't enter idle if multiple cpus are active"); + +static bool skip_off; +module_param(skip_off, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(skip_off, + "Do everything except actually enter the low power state (debugging)"); + +static bool keep_core_on; +module_param(keep_core_on, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(keep_core_on, + "Prevent core powerdomain from entering any low power states (debugging)"); + +static bool keep_mpu_on; +module_param(keep_mpu_on, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(keep_mpu_on, + "Prevent mpu powerdomain from entering any low power states (debugging)"); + +static int max_state; +module_param(max_state, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_state, + "Select deepest power state allowed (0=any, 1=WFI, 2=INA, 3=CSWR, 4=OSWR)"); + +static int only_state; +module_param(only_state, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(only_state, + "Select only power state allowed (0=any, 1=WFI, 2=INA, 3=CSWR, 4=OSWR)"); + +static const int omap4_poke_interrupt[2] = { + OMAP44XX_IRQ_CPUIDLE_POKE0, + OMAP44XX_IRQ_CPUIDLE_POKE1 +}; + +struct omap4_processor_cx { + u8 valid; + u8 type; + u32 exit_latency; + u32 target_residency; + u32 mpu_state; + u32 mpu_logic_state; + u32 core_state; + u32 core_logic_state; + const char *desc; +}; + +struct omap4_processor_cx omap4_power_states[OMAP4_MAX_STATES]; +static struct powerdomain *mpu_pd, *cpu1_pd, *core_pd; +static struct omap4_processor_cx *omap4_idle_requested_cx[NR_CPUS]; +static int omap4_idle_ready_count; +static DEFINE_SPINLOCK(omap4_idle_lock); +static struct clockdomain *cpu1_cd; + +/* + * Raw measured exit latency numbers (us): + * state average max + * C2 383 1068 + * C3 641 1190 + * C4 769 1323 + */ + +static struct cpuidle_params cpuidle_params_table[] = { + /* C1 - CPUx WFI + MPU ON + CORE ON */ + {.exit_latency = 2 + 2, .target_residency = 5, .valid = 1}, + /* C2 - CPU0 INA + CPU1 INA + MPU INA + CORE INA */ + {.exit_latency = 1100, .target_residency = 1100, .valid = 1}, + /* C3 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE CSWR */ + {.exit_latency = 1200, .target_residency = 1200, .valid = 1}, +#ifdef CONFIG_OMAP_ALLOW_OSWR + /* C4 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE OSWR */ + {.exit_latency = 1500, .target_residency = 1500, .valid = 1}, +#else + {.exit_latency = 1500, .target_residency = 1500, .valid = 0}, +#endif +}; + +static void omap4_update_actual_state(struct cpuidle_device *dev, + struct omap4_processor_cx *cx) +{ + int i; + + for (i = 0; i < dev->state_count; i++) { + if (dev->states[i].driver_data == cx) { + dev->last_state = &dev->states[i]; + return; + } + } +} + +static bool omap4_gic_interrupt_pending(void) +{ + void __iomem *gic_cpu = omap4_get_gic_cpu_base(); + + return (__raw_readl(gic_cpu + GIC_CPU_HIGHPRI) != 0x3FF); +} + +/** + * omap4_wfi_until_interrupt + * + * wfi can sometimes return with no interrupts pending, for example on a + * broadcast cache flush or tlb op. This function will call wfi repeatedly + * until an interrupt is actually pending. Returning without looping would + * cause very short idle times to be reported to the idle governor, messing + * with repeating interrupt detection, and causing deep idle states to be + * avoided. + */ +static void omap4_wfi_until_interrupt(void) +{ +retry: + omap_do_wfi(); + + if (!omap4_gic_interrupt_pending()) + goto retry; +} + +/** + * omap4_idle_wait + * + * similar to WFE, but can be woken by an interrupt even though interrupts + * are masked. An "event" is emulated by per-cpu unused interrupt in the GIC. + * Returns false if wake caused by an interrupt, true if by an "event". + */ +static bool omap4_idle_wait(void) +{ + int cpu = hard_smp_processor_id(); + void __iomem *gic_dist = omap4_get_gic_dist_base(); + u32 bit = BIT(omap4_poke_interrupt[cpu] % 32); + u32 reg = (omap4_poke_interrupt[cpu] / 32) * 4; + bool poked; + + /* Unmask the "event" interrupt */ + __raw_writel(bit, gic_dist + GIC_DIST_ENABLE_SET + reg); + + omap4_wfi_until_interrupt(); + + /* Read the "event" interrupt pending bit */ + poked = __raw_readl(gic_dist + GIC_DIST_PENDING_SET + reg) & bit; + + /* Mask the "event" */ + __raw_writel(bit, gic_dist + GIC_DIST_ENABLE_CLEAR + reg); + + /* Clear the event */ + if (poked) + __raw_writel(bit, gic_dist + GIC_DIST_PENDING_CLEAR + reg); + + return poked; +} + +/** + * omap4_poke_cpu + * @cpu: cpu to wake + * + * trigger an "event" to wake a cpu from omap4_idle_wait. + */ +static void omap4_poke_cpu(int cpu) +{ + void __iomem *gic_dist = omap4_get_gic_dist_base(); + u32 bit = BIT(omap4_poke_interrupt[cpu] % 32); + u32 reg = (omap4_poke_interrupt[cpu] / 32) * 4; + + __raw_writel(bit, gic_dist + GIC_DIST_PENDING_SET + reg); +} + +/** + * omap4_enter_idle + * @dev: cpuidle device + * @state: The target state to be programmed + * + * Idle function for C1 state, WFI on a single CPU. + * Called with irqs off, returns with irqs on. + * Returns the amount of time spent in the low power state. + */ +static int omap4_enter_idle_wfi(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + ktime_t preidle, postidle; + + local_fiq_disable(); + + preidle = ktime_get(); + + omap4_wfi_until_interrupt(); + + postidle = ktime_get(); + + local_fiq_enable(); + local_irq_enable(); + + omap4_update_actual_state(dev, &omap4_power_states[OMAP4_STATE_C1]); + + return ktime_to_us(ktime_sub(postidle, preidle)); +} + +static inline bool omap4_all_cpus_idle(void) +{ + int i; + + assert_spin_locked(&omap4_idle_lock); + + for_each_online_cpu(i) + if (omap4_idle_requested_cx[i] == NULL) + return false; + + return true; +} + +static inline struct omap4_processor_cx *omap4_get_idle_state(void) +{ + struct omap4_processor_cx *cx = NULL; + int i; + + assert_spin_locked(&omap4_idle_lock); + + for_each_online_cpu(i) + if (!cx || omap4_idle_requested_cx[i]->type < cx->type) + cx = omap4_idle_requested_cx[i]; + + return cx; +} + +static void omap4_cpu_poke_others(int cpu) +{ + int i; + + for_each_online_cpu(i) + if (i != cpu) + omap4_poke_cpu(i); +} + +static void omap4_cpu_update_state(int cpu, struct omap4_processor_cx *cx) +{ + assert_spin_locked(&omap4_idle_lock); + + omap4_idle_requested_cx[cpu] = cx; + omap4_cpu_poke_others(cpu); +} + +/** + * omap4_enter_idle_primary + * @cx: target idle state + * + * Waits for cpu1 to be off, then starts the transition to the target power + * state for cpu0, mpu and core power domains. + */ +static void omap4_enter_idle_primary(struct omap4_processor_cx *cx) +{ + int cpu = 0; + int ret; + int count = 1000000; + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); + + cpu_pm_enter(); + + if (!keep_mpu_on) { + pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); + omap_set_pwrdm_state(mpu_pd, cx->mpu_state); + } + + if (!keep_core_on) { + pwrdm_set_logic_retst(core_pd, cx->core_logic_state); + omap_set_pwrdm_state(core_pd, cx->core_state); + } + + if (skip_off) + goto out; + + /* spin until cpu1 is really off */ + while ((pwrdm_read_pwrst(cpu1_pd) != PWRDM_POWER_OFF) && count--) + cpu_relax(); + + if (pwrdm_read_pwrst(cpu1_pd) != PWRDM_POWER_OFF) + goto wake_cpu1; + + ret = pwrdm_wait_transition(cpu1_pd); + if (ret) + goto wake_cpu1; + + pr_debug("%s: cpu0 down\n", __func__); + + omap4_enter_sleep(0, PWRDM_POWER_OFF, false); + + pr_debug("%s: cpu0 up\n", __func__); + + /* restore the MPU and CORE states to ON */ + omap_set_pwrdm_state(mpu_pd, PWRDM_POWER_ON); + omap_set_pwrdm_state(core_pd, PWRDM_POWER_ON); + +wake_cpu1: + if (!cpu_is_offline(1)) { + /* + * Work around a ROM bug that causes CPU1 to corrupt the + * gic distributor enable register on 4460 by disabling + * the gic distributor before waking CPU1, and then waiting + * for CPU1 to re-enable the gic distributor before continuing. + */ + if (!cpu_is_omap443x()) + gic_dist_disable(); + + clkdm_wakeup(cpu1_cd); + + if (!cpu_is_omap443x()) + while (gic_dist_disabled()) + cpu_relax(); + + /* + * cpu1 mucks with page tables while it is starting, + * prevent cpu0 executing any processes until cpu1 is up + */ + while (omap4_idle_requested_cx[1] && omap4_idle_ready_count) + cpu_relax(); + } + +out: + cpu_pm_exit(); + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); +} + +/** + * omap4_enter_idle_secondary + * @cpu: target cpu number + * + * Puts target cpu powerdomain into OFF. + */ +static void omap4_enter_idle_secondary(int cpu) +{ + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); + + cpu_pm_enter(); + + pr_debug("%s: cpu1 down\n", __func__); + flush_cache_all(); + dsb(); + + /* TODO: merge CPU1 wakeup masks into CPU0 */ + omap_wakeupgen_irqmask_all(cpu, 1); + gic_cpu_disable(); + + if (!skip_off) + omap4_enter_lowpower(cpu, PWRDM_POWER_OFF); + + omap_wakeupgen_irqmask_all(cpu, 0); + gic_cpu_enable(); + + pr_debug("%s: cpu1 up\n", __func__); + + cpu_pm_exit(); + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); +} + +/** + * omap4_enter_idle - Programs OMAP4 to enter the specified state + * @dev: cpuidle device + * @state: The target state to be programmed + * + * Called from the CPUidle framework to program the device to the + * specified low power state selected by the governor. + * Called with irqs off, returns with irqs on. + * Returns the amount of time spent in the low power state. + */ +static int omap4_enter_idle(struct cpuidle_device *dev, + struct cpuidle_state *state) +{ + struct omap4_processor_cx *cx = cpuidle_get_statedata(state); + struct omap4_processor_cx *actual_cx; + ktime_t preidle, postidle; + bool idle = true; + int cpu = dev->cpu; + + /* + * If disallow_smp_idle is set, revert to the old hotplug governor + * behavior + */ + if (dev->cpu != 0 && disallow_smp_idle) + return omap4_enter_idle_wfi(dev, state); + + /* Clamp the power state at max_state */ + if (max_state > 0 && (cx->type > max_state - 1)) + cx = &omap4_power_states[max_state - 1]; + + /* + * If only_state is set, use wfi if asking for a shallower idle state, + * or the specified state if asking for a deeper idle state + */ + if (only_state > 0) { + if (cx->type < only_state - 1) + cx = &omap4_power_states[OMAP4_STATE_C1]; + else + cx = &omap4_power_states[only_state - 1]; + } + + if (cx->type == OMAP4_STATE_C1) + return omap4_enter_idle_wfi(dev, state); + + preidle = ktime_get(); + + local_fiq_disable(); + + actual_cx = &omap4_power_states[OMAP4_STATE_C1]; + + spin_lock(&omap4_idle_lock); + omap4_cpu_update_state(cpu, cx); + + /* Wait for both cpus to be idle, exiting if an interrupt occurs */ + while (idle && !omap4_all_cpus_idle()) { + spin_unlock(&omap4_idle_lock); + idle = omap4_idle_wait(); + spin_lock(&omap4_idle_lock); + } + + /* + * If we waited for longer than a millisecond, pop out to the governor + * to let it recalculate the desired state. + */ + if (ktime_to_us(ktime_sub(preidle, ktime_get())) > 1000) + idle = false; + + if (!idle) { + omap4_cpu_update_state(cpu, NULL); + spin_unlock(&omap4_idle_lock); + goto out; + } + + /* + * If we go to sleep with an IPI pending, we will lose it. Once we + * reach this point, the other cpu is either already idle or will + * shortly abort idle. If it is already idle it can't send us an IPI, + * so it is safe to check for pending IPIs here. If it aborts idle + * we will abort as well, and any future IPIs will be processed. + */ + if (omap4_gic_interrupt_pending()) { + omap4_cpu_update_state(cpu, NULL); + spin_unlock(&omap4_idle_lock); + goto out; + } + + /* + * Both cpus are probably idle. There is a small chance the other cpu + * just became active. cpu 0 will set omap4_idle_ready_count to 1, + * then each other cpu will increment it. Once a cpu has incremented + * the count, it cannot abort idle and must spin until either the count + * has hit num_online_cpus(), or is reset to 0 by an aborting cpu. + */ + if (cpu == 0) { + BUG_ON(omap4_idle_ready_count != 0); + /* cpu0 requests shared-OFF */ + omap4_idle_ready_count = 1; + /* cpu0 can no longer abort shared-OFF, but cpu1 can */ + + /* wait for cpu1 to ack shared-OFF, or leave idle */ + while (omap4_idle_ready_count != num_online_cpus() && + omap4_idle_ready_count != 0 && omap4_all_cpus_idle()) { + spin_unlock(&omap4_idle_lock); + cpu_relax(); + spin_lock(&omap4_idle_lock); + } + + if (omap4_idle_ready_count != num_online_cpus() || + !omap4_all_cpus_idle()) { + pr_debug("%s: cpu1 aborted: %d %p\n", __func__, + omap4_idle_ready_count, + omap4_idle_requested_cx[1]); + omap4_idle_ready_count = 0; + omap4_cpu_update_state(cpu, NULL); + spin_unlock(&omap4_idle_lock); + goto out; + } + + actual_cx = omap4_get_idle_state(); + spin_unlock(&omap4_idle_lock); + + /* cpu1 is turning itself off, continue with turning cpu0 off */ + + omap4_enter_idle_primary(actual_cx); + + spin_lock(&omap4_idle_lock); + omap4_idle_ready_count = 0; + omap4_cpu_update_state(cpu, NULL); + spin_unlock(&omap4_idle_lock); + } else { + /* wait for cpu0 to request the shared-OFF, or leave idle */ + while ((omap4_idle_ready_count == 0) && omap4_all_cpus_idle()) { + spin_unlock(&omap4_idle_lock); + cpu_relax(); + spin_lock(&omap4_idle_lock); + } + + if (!omap4_all_cpus_idle()) { + pr_debug("%s: cpu0 aborted: %d %p\n", __func__, + omap4_idle_ready_count, + omap4_idle_requested_cx[0]); + omap4_cpu_update_state(cpu, NULL); + spin_unlock(&omap4_idle_lock); + goto out; + } + + pr_debug("%s: cpu1 acks\n", __func__); + /* ack shared-OFF */ + if (omap4_idle_ready_count > 0) + omap4_idle_ready_count++; + BUG_ON(omap4_idle_ready_count > num_online_cpus()); + + while (omap4_idle_ready_count != num_online_cpus() && + omap4_idle_ready_count != 0) { + spin_unlock(&omap4_idle_lock); + cpu_relax(); + spin_lock(&omap4_idle_lock); + } + + if (omap4_idle_ready_count == 0) { + pr_debug("%s: cpu0 aborted: %d %p\n", __func__, + omap4_idle_ready_count, + omap4_idle_requested_cx[0]); + omap4_cpu_update_state(cpu, NULL); + spin_unlock(&omap4_idle_lock); + goto out; + } + + /* cpu1 can no longer abort shared-OFF */ + + actual_cx = omap4_get_idle_state(); + spin_unlock(&omap4_idle_lock); + + omap4_enter_idle_secondary(cpu); + + spin_lock(&omap4_idle_lock); + omap4_idle_ready_count = 0; + omap4_cpu_update_state(cpu, NULL); + spin_unlock(&omap4_idle_lock); + + clkdm_allow_idle(cpu1_cd); + + } + +out: + postidle = ktime_get(); + + omap4_update_actual_state(dev, actual_cx); + + local_irq_enable(); + local_fiq_enable(); + + return ktime_to_us(ktime_sub(postidle, preidle)); +} + +DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); + +/** + * omap4_init_power_states - Initialises the OMAP4 specific C states. + * + * Below is the desciption of each C state. + * C1 : CPUx wfi + MPU inative + Core inactive + */ +void omap4_init_power_states(void) +{ + /* + * C1 - CPU0 WFI + CPU1 OFF + MPU ON + CORE ON + */ + omap4_power_states[OMAP4_STATE_C1].valid = + cpuidle_params_table[OMAP4_STATE_C1].valid; + omap4_power_states[OMAP4_STATE_C1].type = OMAP4_STATE_C1; + omap4_power_states[OMAP4_STATE_C1].exit_latency= + cpuidle_params_table[OMAP4_STATE_C1].exit_latency; + omap4_power_states[OMAP4_STATE_C1].target_residency = + cpuidle_params_table[OMAP4_STATE_C1].target_residency; + omap4_power_states[OMAP4_STATE_C1].desc = "CPU WFI"; + + /* + * C2 - CPU0 INA + CPU1 OFF + MPU INA + CORE INA + */ + omap4_power_states[OMAP4_STATE_C2].valid = + cpuidle_params_table[OMAP4_STATE_C2].valid; + omap4_power_states[OMAP4_STATE_C2].type = OMAP4_STATE_C2; + omap4_power_states[OMAP4_STATE_C2].exit_latency = + cpuidle_params_table[OMAP4_STATE_C2].exit_latency; + omap4_power_states[OMAP4_STATE_C2].target_residency = + cpuidle_params_table[OMAP4_STATE_C2].target_residency; + omap4_power_states[OMAP4_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE; + omap4_power_states[OMAP4_STATE_C2].mpu_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C2].core_state = PWRDM_POWER_INACTIVE; + omap4_power_states[OMAP4_STATE_C2].core_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C2].desc = "CPUs OFF, MPU + CORE INA"; + + /* + * C3 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE CSWR + */ + omap4_power_states[OMAP4_STATE_C3].valid = + cpuidle_params_table[OMAP4_STATE_C3].valid; + omap4_power_states[OMAP4_STATE_C3].type = OMAP4_STATE_C3; + omap4_power_states[OMAP4_STATE_C3].exit_latency = + cpuidle_params_table[OMAP4_STATE_C3].exit_latency; + omap4_power_states[OMAP4_STATE_C3].target_residency = + cpuidle_params_table[OMAP4_STATE_C3].target_residency; + omap4_power_states[OMAP4_STATE_C3].mpu_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C3].mpu_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C3].core_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C3].core_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C3].desc = "CPUs OFF, MPU + CORE CSWR"; + + /* + * C4 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE OSWR + */ + omap4_power_states[OMAP4_STATE_C4].valid = + cpuidle_params_table[OMAP4_STATE_C4].valid; + omap4_power_states[OMAP4_STATE_C4].type = OMAP4_STATE_C4; + omap4_power_states[OMAP4_STATE_C4].exit_latency = + cpuidle_params_table[OMAP4_STATE_C4].exit_latency; + omap4_power_states[OMAP4_STATE_C4].target_residency = + cpuidle_params_table[OMAP4_STATE_C4].target_residency; + omap4_power_states[OMAP4_STATE_C4].mpu_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C4].mpu_logic_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C4].core_state = PWRDM_POWER_RET; + omap4_power_states[OMAP4_STATE_C4].core_logic_state = PWRDM_POWER_OFF; + omap4_power_states[OMAP4_STATE_C4].desc = "CPUs OFF, MPU CSWR + CORE OSWR"; + +} + +struct cpuidle_driver omap4_idle_driver = { + .name = "omap4_idle", + .owner = THIS_MODULE, +}; + +/** + * omap4_idle_init - Init routine for OMAP4 idle + * + * Registers the OMAP4 specific cpuidle driver with the cpuidle + * framework with the valid set of states. + */ +int __init omap4_idle_init(void) +{ + int cpu_id = 0, i, count = 0; + struct omap4_processor_cx *cx; + struct cpuidle_state *state; + struct cpuidle_device *dev; + + mpu_pd = pwrdm_lookup("mpu_pwrdm"); + BUG_ON(!mpu_pd); + cpu1_pd = pwrdm_lookup("cpu1_pwrdm"); + BUG_ON(!cpu1_pd); + cpu1_cd = clkdm_lookup("mpu1_clkdm"); + BUG_ON(!cpu1_cd); + core_pd = pwrdm_lookup("core_pwrdm"); + BUG_ON(!core_pd); + + omap4_init_power_states(); + cpuidle_register_driver(&omap4_idle_driver); + + for_each_possible_cpu(cpu_id) { + dev = &per_cpu(omap4_idle_dev, cpu_id); + dev->cpu = cpu_id; + count = 0; + for (i = OMAP4_STATE_C1; i < OMAP4_MAX_STATES; i++) { + cx = &omap4_power_states[i]; + state = &dev->states[count]; + + if (!cx->valid) + continue; + cpuidle_set_statedata(state, cx); + state->exit_latency = cx->exit_latency; + state->target_residency = cx->target_residency; + state->flags = CPUIDLE_FLAG_TIME_VALID; + if (cx->type == OMAP4_STATE_C1) { + dev->safe_state = state; + state->enter = omap4_enter_idle_wfi; + } else { + state->enter = omap4_enter_idle; + } + + sprintf(state->name, "C%d", count+1); + strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); + count++; + } + + if (!count) + return -EINVAL; + dev->state_count = count; + + if (cpuidle_register_device(dev)) { + pr_err("%s: CPUidle register device failed\n", __func__); + return -EIO; + } + + __raw_writeb(BIT(cpu_id), omap4_get_gic_dist_base() + + GIC_DIST_TARGET + omap4_poke_interrupt[cpu_id]); + } + + return 0; +} +#else +int __init omap4_idle_init(void) +{ + return 0; +} +#endif /* CONFIG_CPU_IDLE */ diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 5b8ca68..cf7a0ba 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -29,13 +29,18 @@ #include <mach/gpio.h> #include <plat/mmc.h> #include <plat/dma.h> +#include <plat/gpu.h> #include <plat/omap_hwmod.h> #include <plat/omap_device.h> #include <plat/omap4-keypad.h> +#include <plat/mcpdm.h> + +#include <sound/omap-abe-dsp.h> #include "mux.h" #include "control.h" #include "devices.h" +#include "dvfs.h" #define L3_MODULES_MAX_LEN 12 #define L3_MODULES 3 @@ -292,6 +297,112 @@ static inline void omap_init_mbox(void) { } static inline void omap_init_sti(void) {} +#if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \ + defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE) + +static struct omap_device_pm_latency omap_mcpdm_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +static void omap_init_mcpdm(void) +{ + struct omap_hwmod *oh; + struct omap_device *od; + struct omap_mcpdm_platform_data *pdata; + char *oh_name = "mcpdm"; + char *dev_name = "omap-mcpdm"; + + oh = omap_hwmod_lookup(oh_name); + if (!oh) { + pr_err("%s: could not look up %s\n", __func__, oh_name); + return; + } + + pdata = kzalloc(sizeof(struct omap_mcpdm_platform_data), GFP_KERNEL); + if (!pdata) { + pr_err("%s: could not allocate platform data\n", __func__); + return; + } + + pdata->was_context_lost = omap_pm_was_context_lost; + + od = omap_device_build(dev_name, -1, oh, pdata, + sizeof(struct omap_mcpdm_platform_data), + omap_mcpdm_latency, + ARRAY_SIZE(omap_mcpdm_latency), 0); + WARN(IS_ERR(od), "could not build omap_device for %s:%s\n", + oh_name, dev_name); +} +#else +static inline void omap_init_mcpdm(void) {} +#endif + +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) || \ + defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + +static struct omap_device_pm_latency omap_aess_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +static void omap_init_aess(void) +{ + struct omap_hwmod *oh; + struct omap_device *od; + struct omap4_abe_dsp_pdata *pdata; + char *oh_name = "aess"; + char *dev_name = "aess"; + + oh = omap_hwmod_lookup(oh_name); + if (!oh) { + pr_err("%s: could not look up %s\n", __func__, oh_name); + return; + } + + pdata = kzalloc(sizeof(struct omap4_abe_dsp_pdata), GFP_KERNEL); + if (!pdata) { + pr_err("%s: could not allocate platform data\n", __func__); + return; + } + + pdata->device_scale = omap_device_scale; + pdata->was_context_lost = omap_pm_was_context_lost; + + od = omap_device_build(dev_name, -1, oh, pdata, + sizeof(struct omap4_abe_dsp_pdata), + omap_aess_latency, + ARRAY_SIZE(omap_aess_latency), 0); + WARN(IS_ERR(od), "could not build omap_device for %s:%s\n", + oh_name, dev_name); + + kfree(pdata); +} +#else +static inline void omap_init_aess(void) {} +#endif + +#if defined CONFIG_ARCH_OMAP4 + +static struct platform_device omap_abe_dai = { + .name = "omap-abe-dai", + .id = -1, +}; + +static inline void omap_init_abe(void) +{ + platform_device_register(&omap_abe_dai); +} +#else +static inline void omap_init_abe(void) {} +#endif + #if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE) static struct platform_device omap_pcm = { @@ -300,6 +411,14 @@ static struct platform_device omap_pcm = { }; /* + * Device for the ASoC OMAP4 HDMI machine driver + */ +static struct platform_device omap4_hdmi_audio = { + .name = "omap4-hdmi-audio", + .id = -1, +}; + +/* * OMAP2420 has 2 McBSP ports * OMAP2430 has 5 McBSP ports * OMAP3 has 5 McBSP ports @@ -313,6 +432,31 @@ OMAP_MCBSP_PLATFORM_DEVICE(5); static void omap_init_audio(void) { + struct omap_hwmod *oh_hdmi; + struct omap_device *od_hdmi, *od_hdmi_codec; + char *oh_hdmi_name = "dss_hdmi"; + char *dev_hdmi_name = "hdmi-audio-dai"; + char *dev_hdmi_codec_name = "omap-hdmi-codec"; + + if (cpu_is_omap44xx()) { + oh_hdmi = omap_hwmod_lookup(oh_hdmi_name); + WARN(!oh_hdmi, "%s: could not find omap_hwmod for %s\n", + __func__, oh_hdmi_name); + + od_hdmi = omap_device_build(dev_hdmi_name, -1, oh_hdmi, NULL, 0, + NULL, 0, false); + WARN(IS_ERR(od_hdmi), "%s: could not build omap_device for %s\n", + __func__, dev_hdmi_name); + + od_hdmi_codec = omap_device_build(dev_hdmi_codec_name, + -1, oh_hdmi, NULL, 0, NULL, 0, false); + + WARN(IS_ERR(od_hdmi_codec), "%s: could not build omap_device for %s\n", + __func__, dev_hdmi_codec_name); + + platform_device_register(&omap4_hdmi_audio); + } + platform_device_register(&omap_mcbsp1); platform_device_register(&omap_mcbsp2); if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) { @@ -329,6 +473,39 @@ static void omap_init_audio(void) static inline void omap_init_audio(void) {} #endif +#if defined(CONFIG_SND_OMAP_SOC_MCASP) || \ + defined(CONFIG_SND_OMAP_SOC_MCASP_MODULE) +static struct omap_device_pm_latency omap_mcasp_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +static void omap_init_mcasp(void) +{ + struct omap_hwmod *oh; + struct omap_device *od; + char *oh_name = "omap-mcasp-dai"; + char *dev_name = "omap-mcasp-dai"; + + oh = omap_hwmod_lookup(oh_name); + if (!oh) { + pr_err("%s: could not look up %s\n", __func__, oh_name); + return; + } + + od = omap_device_build(dev_name, -1, oh, NULL, 0, + omap_mcasp_latency, + ARRAY_SIZE(omap_mcasp_latency), 0); + WARN(IS_ERR(od), "could not build omap_device for %s:%s\n", + oh_name, dev_name); +} +#else +static inline void omap_init_mcasp(void) {} +#endif + #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE) #include <plat/mcspi.h> @@ -673,6 +850,68 @@ static void omap_init_vout(void) static inline void omap_init_vout(void) {} #endif +static struct omap_device_pm_latency omap_gpu_latency[] = { + [0] = { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +static struct platform_device omap_omaplfb_device = { + .name = "omaplfb", + .id = -1, +}; + + +static void omap_init_gpu(void) +{ + struct omap_hwmod *oh; + struct omap_device *od; + int max_omap_gpu_hwmod_name_len = 16; + char oh_name[max_omap_gpu_hwmod_name_len]; + int l; + struct gpu_platform_data *pdata; + char *name = "pvrsrvkm"; + + l = snprintf(oh_name, max_omap_gpu_hwmod_name_len, + "gpu"); + WARN(l >= max_omap_gpu_hwmod_name_len, + "String buffer overflow in GPU device setup\n"); + + oh = omap_hwmod_lookup(oh_name); + if (!oh) { + + pr_err("omap_init_gpu: Could not look up %s\n", oh_name); + return; + } + + pdata = kzalloc(sizeof(struct gpu_platform_data), + GFP_KERNEL); + if (!pdata) { + pr_err("omap_init_gpu: Platform data memory allocation failed\n"); + return; + } + + pdata->device_scale = omap_device_scale; + pdata->device_enable = omap_device_enable; + pdata->device_idle = omap_device_idle; + pdata->device_shutdown = omap_device_shutdown; + + pdata->ovfreqs = 0; + if (cpu_is_omap446x()) + pdata->ovfreqs = 1; + + od = omap_device_build(name, 0, oh, pdata, + sizeof(struct gpu_platform_data), + omap_gpu_latency, ARRAY_SIZE(omap_gpu_latency), 0); + WARN(IS_ERR(od), "Could not build omap_device for %s %s\n", + name, oh_name); + + kfree(pdata); + platform_device_register(&omap_omaplfb_device); +} + /*-------------------------------------------------------------------------*/ static int __init omap2_init_devices(void) @@ -681,9 +920,13 @@ static int __init omap2_init_devices(void) * please keep these calls, and their implementations above, * in alphabetical order so they're easier to sort through. */ + omap_init_mcpdm(); + omap_init_aess(); + omap_init_abe(); omap_init_audio(); omap_init_camera(); omap_init_mbox(); + omap_init_mcasp(); omap_init_mcspi(); omap_init_pmu(); omap_hdq_init(); @@ -691,6 +934,7 @@ static int __init omap2_init_devices(void) omap_init_sham(); omap_init_aes(); omap_init_vout(); + omap_init_gpu(); return 0; } diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 543fcb8..dd91c20 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -25,6 +25,7 @@ #include <video/omapdss.h> #include <plat/omap_hwmod.h> #include <plat/omap_device.h> +#include <plat/omap-pm.h> static struct platform_device omap_display_device = { .name = "omapdss", @@ -42,20 +43,6 @@ static struct omap_device_pm_latency omap_dss_latency[] = { }, }; -/* oh_core is used for getting opt-clocks */ -static struct omap_hwmod *oh_core; - -static bool opt_clock_available(const char *clk_role) -{ - int i; - - for (i = 0; i < oh_core->opt_clks_cnt; i++) { - if (!strcmp(oh_core->opt_clks[i].role, clk_role)) - return true; - } - return false; -} - struct omap_dss_hwmod_data { const char *oh_name; const char *dev_name; @@ -109,16 +96,7 @@ int __init omap_display_init(struct omap_dss_board_info *board_data) oh_count = ARRAY_SIZE(omap4_dss_hwmod_data); } - /* opt_clks are always associated with dss hwmod */ - oh_core = omap_hwmod_lookup("dss_core"); - if (!oh_core) { - pr_err("Could not look up dss_core.\n"); - return -ENODEV; - } - pdata.board_data = board_data; - pdata.board_data->get_last_off_on_transaction_id = NULL; - pdata.opt_clock_available = opt_clock_available; for (i = 0; i < oh_count; i++) { oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name); diff --git a/arch/arm/mach-omap2/dmtimer.c b/arch/arm/mach-omap2/dmtimer.c new file mode 100644 index 0000000..e9cba71 --- /dev/null +++ b/arch/arm/mach-omap2/dmtimer.c @@ -0,0 +1,283 @@ +/** + * OMAP2+ Dual-Mode Timers - platform device registration + * + * Contains first level initialization routines which extracts timers + * information from hwmod database and registers with linux device model. + * It also has low level function to change the timer input clock source. + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * Tarun Kanti DebBarma <tarun.kanti@ti.com> + * Thara Gopinath <thara@ti.com> + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include <plat/dmtimer.h> +#include <plat/omap_device.h> +#include <plat/cpu.h> +#include <plat/omap_hwmod.h> +#include <plat/omap-pm.h> + +#include "powerdomain.h" + +static u8 __initdata system_timer_id; + +/** + * omap2_dm_timer_set_src - change the timer input clock source + * @pdev: timer platform device pointer + * @source: array index of parent clock source + */ +static int omap2_dm_timer_set_src(struct platform_device *pdev, int source) +{ + int ret; + struct dmtimer_platform_data *pdata = pdev->dev.platform_data; + struct clk *new_fclk; + char *fclk_name = "32k_ck"; /* default name */ + + struct clk *fclk = clk_get(&pdev->dev, "fck"); + if (IS_ERR_OR_NULL(fclk)) { + dev_err(&pdev->dev, "%s: %d: clk_get() FAILED\n", + __func__, __LINE__); + return -EINVAL; + } + + switch (source) { + case OMAP_TIMER_SRC_SYS_CLK: + fclk_name = "sys_ck"; + break; + + case OMAP_TIMER_SRC_32_KHZ: + fclk_name = "32k_ck"; + break; + + case OMAP_TIMER_SRC_EXT_CLK: + if (pdata->timer_ip_type == OMAP_TIMER_IP_VERSION_1) { + fclk_name = "alt_ck"; + break; + } + default: + dev_err(&pdev->dev, "%s: %d: invalid clk src.\n", + __func__, __LINE__); + clk_put(fclk); + return -EINVAL; + } + + new_fclk = clk_get(&pdev->dev, fclk_name); + if (IS_ERR_OR_NULL(new_fclk)) { + dev_err(&pdev->dev, "%s: %d: clk_get() %s FAILED\n", + __func__, __LINE__, fclk_name); + clk_put(fclk); + return -EINVAL; + } + + ret = clk_set_parent(fclk, new_fclk); + if (IS_ERR_VALUE(ret)) { + dev_err(&pdev->dev, "%s: clk_set_parent() to %s FAILED\n", + __func__, fclk_name); + ret = -EINVAL; + } + + clk_put(new_fclk); + clk_put(fclk); + + return ret; +} + +struct omap_device_pm_latency omap2_dmtimer_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +/** + * omap_timer_init - build and register timer device with an + * associated timer hwmod + * @oh: timer hwmod pointer to be used to build timer device + * @user: parameter that can be passed from calling hwmod API + * + * Called by omap_hwmod_for_each_by_class to register each of the timer + * devices present in the system. The number of timer devices is known + * by parsing through the hwmod database for a given class name. At the + * end of function call memory is allocated for timer device and it is + * registered to the framework ready to be proved by the driver. + */ +static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) +{ + int id; + int ret = 0; + char *name = "omap_timer"; + struct dmtimer_platform_data *pdata; + struct omap_device *od; + struct omap_secure_timer_dev_attr *secure_timer_dev_attr; + struct powerdomain *pwrdm; + + /* + * Extract the IDs from name field in hwmod database + * and use the same for constructing ids' for the + * timer devices. In a way, we are avoiding usage of + * static variable witin the function to do the same. + * CAUTION: We have to be careful and make sure the + * name in hwmod database does not change in which case + * we might either make corresponding change here or + * switch back static variable mechanism. + */ + sscanf(oh->name, "timer%2d", &id); + if (unlikely(id == system_timer_id)) + return ret; + + pr_debug("%s: %s\n", __func__, oh->name); + + /* do not register secure timer */ + secure_timer_dev_attr = oh->dev_attr; + if (secure_timer_dev_attr && secure_timer_dev_attr->is_secure_timer) + return ret; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + pr_err("%s: No memory for [%s]\n", __func__, oh->name); + return -ENOMEM; + } + pdata->set_timer_src = omap2_dm_timer_set_src; + pdata->timer_ip_type = oh->class->rev; + pwrdm = omap_hwmod_get_pwrdm(oh); + if (!pwrdm) { + pr_debug("%s: could not find pwrdm for (%s) in omap hwmod!\n", + __func__, oh->name); + return -EINVAL; + } + pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm); + + od = omap_device_build(name, id, oh, pdata, sizeof(*pdata), + omap2_dmtimer_latency, + ARRAY_SIZE(omap2_dmtimer_latency), + pdata->is_early_init); + + if (IS_ERR(od)) { + pr_err("%s: Can't build omap_device for %s: %s.\n", + __func__, name, oh->name); + ret = -EINVAL; + } + + kfree(pdata); + + return ret; +} + +/** + * omap2_system_timer_init - top level system timer initialization + * called from omap2_gp_timer_init() in timer-gp.c + * @id : system timer id + * + * This function does hwmod setup for the system timer entry needed + * prior to building and registering the device. After the device is + * registered early probe initiated. + */ +int __init omap2_system_timer_init(u8 id) +{ + int ret = 0; + char *name = "omap_timer"; + struct dmtimer_platform_data *pdata; + struct omap_device *od; + struct omap_hwmod *oh; + char system_timer_name[8]; /* 8 = sizeof("timerXX0") */ + + system_timer_id = id; + + sprintf(system_timer_name, "timer%d", id); + ret = omap_hwmod_setup_one(system_timer_name); + if (ret) { + pr_err("%s: omap_hwmod_setup_one(%s) failed.\n", + __func__, system_timer_name); + return ret; + } + oh = omap_hwmod_lookup(system_timer_name); + if (!oh) { + pr_debug("%s: could not find (%s) in omap_hwmod_list!\n", + __func__, system_timer_name); + return -EINVAL; + } + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + pr_err("%s: No memory for [%s]\n", __func__, oh->name); + return -ENOMEM; + } + pdata->is_early_init = 1; + pdata->set_timer_src = omap2_dm_timer_set_src; + pdata->timer_ip_type = oh->class->rev; + pdata->needs_manual_reset = 0; + + od = omap_device_build(name, id, oh, pdata, sizeof(*pdata), + omap2_dmtimer_latency, + ARRAY_SIZE(omap2_dmtimer_latency), + pdata->is_early_init); + + if (IS_ERR(od)) { + pr_err("%s: Can't build omap_device for %s: %s.\n", + __func__, name, oh->name); + ret = -EINVAL; + } + + kfree(pdata); + + if (!ret) { + early_platform_driver_register_all("earlytimer"); + early_platform_driver_probe("earlytimer", 1, 0); + } + + return 0; +} + +/** + * omap2_system_timer_set_src - change the timer input clock source + * Allow system timer to program clock source before pm_runtime + * framework is available during system boot. + * @timer: pointer to struct omap_dm_timer + * @source: array index of parent clock source + */ +int __init omap2_system_timer_set_src(struct omap_dm_timer *timer, int source) +{ + int ret; + + if (IS_ERR_OR_NULL(timer) || IS_ERR_OR_NULL(timer->fclk)) + return -EINVAL; + + clk_disable(timer->fclk); + ret = omap2_dm_timer_set_src(timer->pdev, source); + clk_enable(timer->fclk); + + return ret; +} + +/** + * omap2_dm_timer_init - top level regular device initialization + * + * Uses dedicated hwmod api to parse through hwmod database for + * given class name and then build and register the timer device. + */ +static int __init omap2_dm_timer_init(void) +{ + int ret; + + ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); + if (unlikely(ret)) { + pr_err("%s: device registration failed.\n", __func__); + return -EINVAL; + } + + return 0; +} +arch_initcall(omap2_dm_timer_init); diff --git a/arch/arm/mach-omap2/dmtimer.h b/arch/arm/mach-omap2/dmtimer.h new file mode 100644 index 0000000..4cfd580 --- /dev/null +++ b/arch/arm/mach-omap2/dmtimer.h @@ -0,0 +1,32 @@ +/** + * OMAP Dual-Mode Timers - early initialization interface + * + * Function interface called first to start dmtimer early initialization. + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * Tarun Kanti DebBarma <tarun.kanti@ti.com> + * Thara Gopinath <thara@ti.com> + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __ASM_ARCH_OMAP2_DMTIMER_H +#define __ASM_ARCH_OMAP2_DMTIMER_H + +#include <plat/dmtimer.h> + +/* + * dmtimer is required during early part of boot sequence even before + * device model and pm_runtime if fully up and running. This function + * is called from following sequence: + * start_kernel()->time_init()->timer->init()->omap2_gp_timer_init() + */ +extern int __init omap2_system_timer_init(u8 id); +extern int __init omap2_system_timer_set_src(struct omap_dm_timer *, int); +#endif diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index f77022b..7fb0d21 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -32,8 +32,10 @@ #include <plat/clock.h> #include "clock.h" +#include "cm2_44xx.h" #include "cm2xxx_3xxx.h" #include "cm-regbits-34xx.h" +#include "cm-regbits-44xx.h" /* CM_AUTOIDLE_PLL*.AUTO_* bit values */ #define DPLL_AUTOIDLE_DISABLE 0x0 @@ -61,22 +63,76 @@ static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits) static int _omap3_wait_dpll_status(struct clk *clk, u8 state) { const struct dpll_data *dd; - int i = 0; + int i; int ret = -EINVAL; + bool first_time = true; + u32 reg; + u32 orig_cm_div_m2_dpll_usb; + u32 orig_cm_clkdcoldo_dpll_usb; +retry: dd = clk->dpll_data; state <<= __ffs(dd->idlest_mask); + i = 0; while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) && i < MAX_DPLL_WAIT_TRIES) { i++; udelay(1); } + /* restore back old values if hit work-around */ + if (!first_time) { + __raw_writel(orig_cm_div_m2_dpll_usb, + OMAP4430_CM_DIV_M2_DPLL_USB); + __raw_writel(orig_cm_clkdcoldo_dpll_usb, + OMAP4430_CM_CLKDCOLDO_DPLL_USB); + } + if (i == MAX_DPLL_WAIT_TRIES) { printk(KERN_ERR "clock: %s failed transition to '%s'\n", clk->name, (state) ? "locked" : "bypassed"); + + /* Try Error Recovery: for failing usbdpll locking */ + if (!strcmp(clk->name, "dpll_usb_ck")) { + + reg = __raw_readl(dd->mult_div1_reg); + + /* Put in MN bypass */ + _omap3_dpll_write_clken(clk, DPLL_MN_BYPASS); + i = 0; + while (!(__raw_readl(dd->idlest_reg) & (1 << OMAP4430_ST_MN_BYPASS_SHIFT)) && + i < MAX_DPLL_WAIT_TRIES) { + i++; + udelay(1); + } + + /* MN bypass looses contents of CM_CLKSEL_DPLL_USB */ + __raw_writel(reg, dd->mult_div1_reg); + + /* Force generate request to PRCM: put in Force mode */ + + /* a) CM_DIV_M2_DPLL_USB.DPLL_CLKOUT_GATE_CTRL = 1 */ + orig_cm_div_m2_dpll_usb = __raw_readl(OMAP4430_CM_DIV_M2_DPLL_USB); + __raw_writel(orig_cm_div_m2_dpll_usb | + (1 << OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT), + OMAP4430_CM_DIV_M2_DPLL_USB); + + /* b) CM_CLKDCOLDO_DPLL_USB.DPLL_CLKDCOLDO_GATE_CTRL = 1 */ + orig_cm_clkdcoldo_dpll_usb = __raw_readl(OMAP4430_CM_CLKDCOLDO_DPLL_USB); + __raw_writel(orig_cm_clkdcoldo_dpll_usb | + (1 << OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT), + OMAP4430_CM_CLKDCOLDO_DPLL_USB); + + /* Put back to locked mode */ + _omap3_dpll_write_clken(clk, DPLL_LOCKED); + + if (first_time) { + first_time = false; + goto retry; + } + } } else { pr_debug("clock: %s transition to '%s' in %d loops\n", clk->name, (state) ? "locked" : "bypassed", i); @@ -135,11 +191,20 @@ static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n) */ static int _omap3_noncore_dpll_lock(struct clk *clk) { + const struct dpll_data *dd; u8 ai; - int r; + u8 state = 1; + int r = 0; pr_debug("clock: locking DPLL %s\n", clk->name); + dd = clk->dpll_data; + state <<= __ffs(dd->idlest_mask); + + /* Check if already locked */ + if ((__raw_readl(dd->idlest_reg) & dd->idlest_mask) == state) + goto done; + ai = omap3_dpll_autoidle_read(clk); omap3_dpll_deny_idle(clk); @@ -151,6 +216,7 @@ static int _omap3_noncore_dpll_lock(struct clk *clk) if (ai) omap3_dpll_allow_idle(clk); +done: return r; } @@ -455,7 +521,7 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) new_parent = dd->clk_bypass; } else { if (dd->last_rounded_rate != rate) - omap2_dpll_round_rate(clk, rate); + rate = clk->round_rate(clk, rate); if (dd->last_rounded_rate == 0) return -EINVAL; diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 4e4da61..d4cfe2a 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -14,12 +14,219 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/bitops.h> - +#include <linux/spinlock.h> #include <plat/cpu.h> #include <plat/clock.h> +#include <plat/common.h> + +#include <mach/emif.h> +#include <mach/omap4-common.h> #include "clock.h" +#include "clock44xx.h" +#include "cm.h" +#include "cm44xx.h" +#include "cm1_44xx.h" +#include "cm2_44xx.h" +#include "cminst44xx.h" +#include "clock44xx.h" +#include "clockdomain.h" #include "cm-regbits-44xx.h" +#include "prcm44xx.h" + +#define MAX_FREQ_UPDATE_TIMEOUT 100000 + +static struct clockdomain *l3_emif_clkdm; +static DEFINE_SPINLOCK(l3_emif_lock); + +/** + * omap4_core_dpll_m2_set_rate - set CORE DPLL M2 divider + * @clk: struct clk * of DPLL to set + * @rate: rounded target rate + * + * Programs the CM shadow registers to update CORE DPLL M2 + * divider. M2 divider is used to clock external DDR and its + * reconfiguration on frequency change is managed through a + * hardware sequencer. This is managed by the PRCM with EMIF + * uding shadow registers. + * Returns -EINVAL/-1 on error and 0 on success. + */ +int omap4_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) +{ + int i = 0; + u32 validrate = 0, shadow_freq_cfg1 = 0, new_div = 0; + unsigned long flags; + + if (!clk || !rate) + return -EINVAL; + + validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); + if (validrate != rate) + return -EINVAL; + + /* Just to avoid look-up on every call to speed up */ + if (!l3_emif_clkdm) { + l3_emif_clkdm = clkdm_lookup("l3_emif_clkdm"); + if (!l3_emif_clkdm) { + pr_err("%s: clockdomain lookup failed\n", __func__); + return -EINVAL; + } + } + + spin_lock_irqsave(&l3_emif_lock, flags); + + /* Configures MEMIF domain in SW_WKUP */ + clkdm_wakeup(l3_emif_clkdm); + + /* + * Errata ID: i728 + * + * DESCRIPTION: + * + * If during a small window the following three events occur: + * + * 1) The EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM SR_TIMING counter expires + * 2) Frequency change update is requested CM_SHADOW_FREQ_CONFIG1 + * FREQ_UPDATE set to 1 + * 3) OCP access is requested + * + * There will be clock instability on the DDR interface. + * + * WORKAROUND: + * + * Prevent event 1) while event 2) is happening. + * + * Disable the self-refresh when requesting a frequency change. + * Before requesting a frequency change, program + * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0 + * (omap_emif_frequency_pre_notify) + * + * When the frequency change is completed, reprogram + * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2. + * (omap_emif_frequency_post_notify) + */ + omap_emif_frequency_pre_notify(); + + /* + * Program EMIF timing parameters in EMIF shadow registers + * for targetted DRR clock. + * DDR Clock = core_dpll_m2 / 2 + */ + omap_emif_setup_registers(validrate >> 1, LPDDR2_VOLTAGE_STABLE); + + /* + * FREQ_UPDATE sequence: + * - DLL_OVERRIDE=0 (DLL lock & code must not be overridden + * after CORE DPLL lock) + * - DLL_RESET=1 (DLL must be reset upon frequency change) + * - DPLL_CORE_M2_DIV with same value as the one already + * in direct register + * - DPLL_CORE_DPLL_EN=0x7 (to make CORE DPLL lock) + * - FREQ_UPDATE=1 (to start HW sequence) + */ + shadow_freq_cfg1 = (1 << OMAP4430_DLL_RESET_SHIFT) | + (new_div << OMAP4430_DPLL_CORE_M2_DIV_SHIFT) | + (DPLL_LOCKED << OMAP4430_DPLL_CORE_DPLL_EN_SHIFT) | + (1 << OMAP4430_FREQ_UPDATE_SHIFT); + shadow_freq_cfg1 &= ~OMAP4430_DLL_OVERRIDE_MASK; + __raw_writel(shadow_freq_cfg1, OMAP4430_CM_SHADOW_FREQ_CONFIG1); + + /* wait for the configuration to be applied */ + omap_test_timeout(((__raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1) + & OMAP4430_FREQ_UPDATE_MASK) == 0), + MAX_FREQ_UPDATE_TIMEOUT, i); + + /* Re-enable DDR self refresh */ + omap_emif_frequency_post_notify(); + + /* Configures MEMIF domain back to HW_WKUP */ + clkdm_allow_idle(l3_emif_clkdm); + + spin_unlock_irqrestore(&l3_emif_lock, flags); + + if (i == MAX_FREQ_UPDATE_TIMEOUT) { + pr_err("%s: Frequency update for CORE DPLL M2 change failed\n", + __func__); + return -1; + } + + /* Update the clock change */ + clk->rate = validrate; + + return 0; +} + + +/** + * omap4_prcm_freq_update - set freq_update bit + * + * Programs the CM shadow registers to update EMIF + * parametrs. Few usecase only few registers needs to + * be updated using prcm freq update sequence. + * EMIF read-idle control and zq-config needs to be + * updated for temprature alerts and voltage change + * Returns -1 on error and 0 on success. + */ +int omap4_prcm_freq_update(void) +{ + u32 shadow_freq_cfg1; + int i = 0; + unsigned long flags; + + if (!l3_emif_clkdm) { + pr_err("%s: clockdomain lookup failed\n", __func__); + return -EINVAL; + } + + spin_lock_irqsave(&l3_emif_lock, flags); + /* Configures MEMIF domain in SW_WKUP */ + clkdm_wakeup(l3_emif_clkdm); + + /* Disable DDR self refresh (Errata ID: i728) */ + omap_emif_frequency_pre_notify(); + + /* + * FREQ_UPDATE sequence: + * - DLL_OVERRIDE=0 (DLL lock & code must not be overridden + * after CORE DPLL lock) + * - FREQ_UPDATE=1 (to start HW sequence) + */ + shadow_freq_cfg1 = __raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1); + shadow_freq_cfg1 |= (1 << OMAP4430_DLL_RESET_SHIFT) | + (1 << OMAP4430_FREQ_UPDATE_SHIFT); + shadow_freq_cfg1 &= ~OMAP4430_DLL_OVERRIDE_MASK; + __raw_writel(shadow_freq_cfg1, OMAP4430_CM_SHADOW_FREQ_CONFIG1); + + /* wait for the configuration to be applied */ + omap_test_timeout(((__raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1) + & OMAP4430_FREQ_UPDATE_MASK) == 0), + MAX_FREQ_UPDATE_TIMEOUT, i); + + /* Re-enable DDR self refresh */ + omap_emif_frequency_post_notify(); + + /* Configures MEMIF domain back to HW_WKUP */ + clkdm_allow_idle(l3_emif_clkdm); + + spin_unlock_irqrestore(&l3_emif_lock, flags); + + if (i == MAX_FREQ_UPDATE_TIMEOUT) { + pr_err("%s: Frequency update failed (call from %pF)\n", + __func__, (void *)_RET_IP_); + return -1; + } + + return 0; +} + +/* Use a very high retry count - we should not hit this condition */ +#define MAX_DPLL_WAIT_TRIES 1000000 + +#define OMAP_1_5GHz 1500000000 +#define OMAP_1_2GHz 1200000000 +#define OMAP_1GHz 1000000000 +#define OMAP_920MHz 920000000 +#define OMAP_748MHz 748000000 /* Supported only on OMAP4 */ int omap4_dpllmx_gatectrl_read(struct clk *clk) @@ -82,3 +289,370 @@ const struct clkops clkops_omap4_dpllmx_ops = { .deny_idle = omap4_dpllmx_deny_gatectrl, }; +static void omap4460_mpu_dpll_update_children(unsigned long rate) +{ + u32 v; + + /* + * The interconnect frequency to EMIF should + * be switched between MPU clk divide by 4 (for + * frequencies higher than 920Mhz) and MPU clk divide + * by 2 (for frequencies lower than or equal to 920Mhz) + * Also the async bridge to ABE must be MPU clk divide + * by 8 for MPU clk > 748Mhz and MPU clk divide by 4 + * for lower frequencies. + */ + v = __raw_readl(OMAP4430_CM_MPU_MPU_CLKCTRL); + if (rate > OMAP_920MHz) + v |= OMAP4460_CLKSEL_EMIF_DIV_MODE_MASK; + else + v &= ~OMAP4460_CLKSEL_EMIF_DIV_MODE_MASK; + + if (rate > OMAP_748MHz) + v |= OMAP4460_CLKSEL_ABE_DIV_MODE_MASK; + else + v &= ~OMAP4460_CLKSEL_ABE_DIV_MODE_MASK; + __raw_writel(v, OMAP4430_CM_MPU_MPU_CLKCTRL); +} + +int omap4460_mpu_dpll_set_rate(struct clk *clk, unsigned long rate) +{ + struct dpll_data *dd; + u32 v; + unsigned long dpll_rate; + + if (!clk || !rate || !clk->parent) + return -EINVAL; + + dd = clk->parent->dpll_data; + + if (!dd) + return -EINVAL; + + if (!clk->parent->set_rate) + return -EINVAL; + + if (rate > clk->rate) + omap4460_mpu_dpll_update_children(rate); + + /* + * On OMAP4460, to obtain MPU DPLL frequency higher + * than 1GHz, DCC (Duty Cycle Correction) needs to + * be enabled. + * And needs to be kept disabled for < 1 Ghz. + */ + dpll_rate = omap2_get_dpll_rate(clk->parent); + if (rate <= OMAP_1_5GHz) { + /* If DCC is enabled, disable it */ + v = __raw_readl(dd->mult_div1_reg); + if (v & OMAP4460_DCC_EN_MASK) { + v &= ~OMAP4460_DCC_EN_MASK; + __raw_writel(v, dd->mult_div1_reg); + } + + if (rate != dpll_rate) + clk->parent->set_rate(clk->parent, rate); + } else { + /* + * On 4460, the MPU clk for frequencies higher than 1Ghz + * is sourced from CLKOUTX2_M3, instead of CLKOUT_M2, while + * value of M3 is fixed to 1. Hence for frequencies higher + * than 1 Ghz, lock the DPLL at half the rate so the + * CLKOUTX2_M3 then matches the requested rate. + */ + if (rate != dpll_rate * 2) + clk->parent->set_rate(clk->parent, rate / 2); + + v = __raw_readl(dd->mult_div1_reg); + v &= ~OMAP4460_DCC_COUNT_MAX_MASK; + v |= (5 << OMAP4460_DCC_COUNT_MAX_SHIFT); + __raw_writel(v, dd->mult_div1_reg); + + v |= OMAP4460_DCC_EN_MASK; + __raw_writel(v, dd->mult_div1_reg); + } + + if (rate < clk->rate) + omap4460_mpu_dpll_update_children(rate); + + clk->rate = rate; + + return 0; +} + +long omap4460_mpu_dpll_round_rate(struct clk *clk, unsigned long rate) +{ + if (!clk || !rate || !clk->parent) + return -EINVAL; + + if (clk->parent->round_rate) + return clk->parent->round_rate(clk->parent, rate); + else + return 0; +} + +unsigned long omap4460_mpu_dpll_recalc(struct clk *clk) +{ + struct dpll_data *dd; + u32 v; + + if (!clk || !clk->parent) + return -EINVAL; + + dd = clk->parent->dpll_data; + + if (!dd) + return -EINVAL; + + v = __raw_readl(dd->mult_div1_reg); + if (v & OMAP4460_DCC_EN_MASK) + return omap2_get_dpll_rate(clk->parent) * 2; + else + return omap2_get_dpll_rate(clk->parent); +} + +unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk) +{ + u32 v; + unsigned long rate; + struct dpll_data *dd; + + if (!clk || !clk->dpll_data) + return -EINVAL; + + dd = clk->dpll_data; + + rate = omap2_get_dpll_rate(clk); + + /* regm4xen adds a multiplier of 4 to DPLL calculations */ + v = __raw_readl(dd->control_reg); + if (v & OMAP4430_DPLL_REGM4XEN_MASK) + rate *= OMAP4430_REGM4XEN_MULT; + + return rate; +} + +long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) +{ + u32 v; + struct dpll_data *dd; + + if (!clk || !clk->dpll_data) + return -EINVAL; + + dd = clk->dpll_data; + + /* regm4xen adds a multiplier of 4 to DPLL calculations */ + v = __raw_readl(dd->control_reg) & OMAP4430_DPLL_REGM4XEN_MASK; + + if (v) + target_rate = target_rate / OMAP4430_REGM4XEN_MULT; + + omap2_dpll_round_rate(clk, target_rate); + + if (v) + clk->dpll_data->last_rounded_rate *= OMAP4430_REGM4XEN_MULT; + + return clk->dpll_data->last_rounded_rate; +} + +struct dpll_reg_tuple { + u16 addr; + u32 val; +}; + +struct omap4_dpll_regs { + char *name; + u32 mod_partition; + u32 mod_inst; + struct dpll_reg_tuple clkmode; + struct dpll_reg_tuple autoidle; + struct dpll_reg_tuple idlest; + struct dpll_reg_tuple clksel; + struct dpll_reg_tuple div_m2; + struct dpll_reg_tuple div_m3; + struct dpll_reg_tuple div_m4; + struct dpll_reg_tuple div_m5; + struct dpll_reg_tuple div_m6; + struct dpll_reg_tuple div_m7; + struct dpll_reg_tuple clkdcoldo; +}; + +static struct omap4_dpll_regs dpll_regs[] = { + /* MPU DPLL */ + { .name = "mpu", + .mod_partition = OMAP4430_CM1_PARTITION, + .mod_inst = OMAP4430_CM1_CKGEN_INST, + .clkmode = {.addr = OMAP4_CM_CLKMODE_DPLL_MPU_OFFSET}, + .autoidle = {.addr = OMAP4_CM_AUTOIDLE_DPLL_MPU_OFFSET}, + .idlest = {.addr = OMAP4_CM_IDLEST_DPLL_MPU_OFFSET}, + .clksel = {.addr = OMAP4_CM_CLKSEL_DPLL_MPU_OFFSET}, + .div_m2 = {.addr = OMAP4_CM_DIV_M2_DPLL_MPU_OFFSET}, + }, + /* IVA DPLL */ + { .name = "iva", + .mod_partition = OMAP4430_CM1_PARTITION, + .mod_inst = OMAP4430_CM1_CKGEN_INST, + .clkmode = {.addr = OMAP4_CM_CLKMODE_DPLL_IVA_OFFSET}, + .autoidle = {.addr = OMAP4_CM_AUTOIDLE_DPLL_IVA_OFFSET}, + .idlest = {.addr = OMAP4_CM_IDLEST_DPLL_IVA_OFFSET}, + .clksel = {.addr = OMAP4_CM_CLKSEL_DPLL_IVA_OFFSET}, + .div_m4 = {.addr = OMAP4_CM_DIV_M4_DPLL_IVA_OFFSET}, + .div_m5 = {.addr = OMAP4_CM_DIV_M5_DPLL_IVA_OFFSET}, + }, + /* ABE DPLL */ + { .name = "abe", + .mod_partition = OMAP4430_CM1_PARTITION, + .mod_inst = OMAP4430_CM1_CKGEN_INST, + .clkmode = {.addr = OMAP4_CM_CLKMODE_DPLL_ABE_OFFSET}, + .autoidle = {.addr = OMAP4_CM_AUTOIDLE_DPLL_ABE_OFFSET}, + .idlest = {.addr = OMAP4_CM_IDLEST_DPLL_ABE_OFFSET}, + .clksel = {.addr = OMAP4_CM_CLKSEL_DPLL_ABE_OFFSET}, + .div_m2 = {.addr = OMAP4_CM_DIV_M2_DPLL_ABE_OFFSET}, + .div_m3 = {.addr = OMAP4_CM_DIV_M3_DPLL_ABE_OFFSET}, + }, + /* USB DPLL */ + { .name = "usb", + .mod_partition = OMAP4430_CM2_PARTITION, + .mod_inst = OMAP4430_CM2_CKGEN_INST, + .clkmode = {.addr = OMAP4_CM_CLKMODE_DPLL_USB_OFFSET}, + .autoidle = {.addr = OMAP4_CM_AUTOIDLE_DPLL_USB_OFFSET}, + .idlest = {.addr = OMAP4_CM_IDLEST_DPLL_USB_OFFSET}, + .clksel = {.addr = OMAP4_CM_CLKSEL_DPLL_USB_OFFSET}, + .div_m2 = {.addr = OMAP4_CM_DIV_M2_DPLL_USB_OFFSET}, + .clkdcoldo = {.addr = OMAP4_CM_CLKDCOLDO_DPLL_USB_OFFSET}, + }, + /* PER DPLL */ + { .name = "per", + .mod_partition = OMAP4430_CM2_PARTITION, + .mod_inst = OMAP4430_CM2_CKGEN_INST, + .clkmode = {.addr = OMAP4_CM_CLKMODE_DPLL_PER_OFFSET}, + .autoidle = {.addr = OMAP4_CM_AUTOIDLE_DPLL_PER_OFFSET}, + .idlest = {.addr = OMAP4_CM_IDLEST_DPLL_PER_OFFSET}, + .clksel = {.addr = OMAP4_CM_CLKSEL_DPLL_PER_OFFSET}, + .div_m2 = {.addr = OMAP4_CM_DIV_M2_DPLL_PER_OFFSET}, + .div_m3 = {.addr = OMAP4_CM_DIV_M3_DPLL_PER_OFFSET}, + .div_m4 = {.addr = OMAP4_CM_DIV_M4_DPLL_PER_OFFSET}, + .div_m5 = {.addr = OMAP4_CM_DIV_M5_DPLL_PER_OFFSET}, + .div_m6 = {.addr = OMAP4_CM_DIV_M6_DPLL_PER_OFFSET}, + .div_m7 = {.addr = OMAP4_CM_DIV_M7_DPLL_PER_OFFSET}, + }, +}; + +static inline void omap4_dpll_store_reg(struct omap4_dpll_regs *dpll_reg, + struct dpll_reg_tuple *tuple) +{ + if (tuple->addr) + tuple->val = + omap4_cminst_read_inst_reg(dpll_reg->mod_partition, + dpll_reg->mod_inst, tuple->addr); +} + +void omap4_dpll_prepare_off(void) +{ + u32 i; + struct omap4_dpll_regs *dpll_reg = dpll_regs; + + for (i = 0; i < ARRAY_SIZE(dpll_regs); i++, dpll_reg++) { + omap4_dpll_store_reg(dpll_reg, &dpll_reg->clkmode); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->autoidle); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->clksel); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m2); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m3); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m4); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m5); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m6); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m7); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->clkdcoldo); + omap4_dpll_store_reg(dpll_reg, &dpll_reg->idlest); + } +} + +static void omap4_dpll_print_reg(struct omap4_dpll_regs *dpll_reg, char *name, + struct dpll_reg_tuple *tuple) +{ + if (tuple->addr) + pr_warn("%s - Address offset = 0x%08x, value=0x%08x\n", name, + tuple->addr, tuple->val); +} + +static void omap4_dpll_dump_regs(struct omap4_dpll_regs *dpll_reg) +{ + pr_warn("%s: Unable to lock dpll %s[part=%x inst=%x]:\n", + __func__, dpll_reg->name, dpll_reg->mod_partition, + dpll_reg->mod_inst); + omap4_dpll_print_reg(dpll_reg, "clksel", &dpll_reg->clksel); + omap4_dpll_print_reg(dpll_reg, "div_m2", &dpll_reg->div_m2); + omap4_dpll_print_reg(dpll_reg, "div_m3", &dpll_reg->div_m3); + omap4_dpll_print_reg(dpll_reg, "div_m4", &dpll_reg->div_m4); + omap4_dpll_print_reg(dpll_reg, "div_m5", &dpll_reg->div_m5); + omap4_dpll_print_reg(dpll_reg, "div_m6", &dpll_reg->div_m6); + omap4_dpll_print_reg(dpll_reg, "div_m7", &dpll_reg->div_m7); + omap4_dpll_print_reg(dpll_reg, "clkdcoldo", &dpll_reg->clkdcoldo); + omap4_dpll_print_reg(dpll_reg, "clkmode", &dpll_reg->clkmode); + omap4_dpll_print_reg(dpll_reg, "autoidle", &dpll_reg->autoidle); + if (dpll_reg->idlest.addr) + pr_warn("idlest - Address offset = 0x%08x, before val=0x%08x" + " after = 0x%08x\n", dpll_reg->idlest.addr, + dpll_reg->idlest.val, + omap4_cminst_read_inst_reg(dpll_reg->mod_partition, + dpll_reg->mod_inst, + dpll_reg->idlest.addr)); +} + +static void omap4_wait_dpll_lock(struct omap4_dpll_regs *dpll_reg) +{ + int j = 0; + + /* Return if we dont need to lock. */ + if ((dpll_reg->clkmode.val & OMAP4430_DPLL_EN_MASK) != + DPLL_LOCKED << OMAP4430_DPLL_EN_SHIFT); + return; + + while ((omap4_cminst_read_inst_reg(dpll_reg->mod_partition, + dpll_reg->mod_inst, + dpll_reg->idlest.addr) + & OMAP4430_ST_DPLL_CLK_MASK) != + 0x1 << OMAP4430_ST_DPLL_CLK_SHIFT + && j < MAX_DPLL_WAIT_TRIES) { + j++; + udelay(1); + } + + /* if we are unable to lock, warn and move on.. */ + if (j == MAX_DPLL_WAIT_TRIES) + omap4_dpll_dump_regs(dpll_reg); +} + +static inline void omap4_dpll_restore_reg(struct omap4_dpll_regs *dpll_reg, + struct dpll_reg_tuple *tuple) +{ + if (tuple->addr) + omap4_cminst_write_inst_reg(tuple->val, dpll_reg->mod_partition, + dpll_reg->mod_inst, tuple->addr); +} + +void omap4_dpll_resume_off(void) +{ + u32 i; + struct omap4_dpll_regs *dpll_reg = dpll_regs; + + for (i = 0; i < ARRAY_SIZE(dpll_regs); i++, dpll_reg++) { + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->clksel); + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m2); + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m3); + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m4); + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m5); + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m6); + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m7); + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->clkdcoldo); + + /* Restore clkmode after the above registers are restored */ + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->clkmode); + + omap4_wait_dpll_lock(dpll_reg); + + /* Restore autoidle settings after the dpll is locked */ + omap4_dpll_restore_reg(dpll_reg, &dpll_reg->autoidle); + } +} diff --git a/arch/arm/mach-omap2/dvfs.c b/arch/arm/mach-omap2/dvfs.c new file mode 100644 index 0000000..e00032b --- /dev/null +++ b/arch/arm/mach-omap2/dvfs.c @@ -0,0 +1,1314 @@ +/* + * OMAP3/OMAP4 DVFS Management Routines + * + * Author: Vishwanath BS <vishwanath.bs@ti.com> + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Vishwanath BS <vishwanath.bs@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/spinlock.h> +#include <linux/plist.h> +#include <linux/slab.h> +#include <linux/opp.h> +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <plat/common.h> +#include <plat/omap_device.h> +#include <plat/omap_hwmod.h> +#include <plat/clock.h> +#include "dvfs.h" +#include "smartreflex.h" +#include "powerdomain.h" +#include "pm.h" + +/** + * DOC: Introduction + * ================= + * DVFS is a technique that uses the optimal operating frequency and voltage to + * allow a task to be performed in the required amount of time. + * OMAP processors have voltage domains whose voltage can be scaled to + * various levels depending on which the operating frequencies of certain + * devices belonging to the domain will also need to be scaled. This voltage + * frequency tuple is known as Operating Performance Point (OPP). A device + * can have multiple OPP's. Also a voltage domain could be shared between + * multiple devices. Also there could be dependencies between various + * voltage domains for maintaining system performance like VDD<X> + * should be at voltage v1 when VDD<Y> is at voltage v2. + * + * The design of this framework takes into account all the above mentioned + * points. To summarize the basic design of DVFS framework:- + * + * 1. Have device opp tables for each device whose operating frequency can be + * scaled. This is easy now due to the existance of hwmod layer which + * allow storing of device specific info. The device opp tables contain + * the opp pairs (frequency voltage tuples), the voltage domain pointer + * to which the device belongs to, the device specific set_rate and + * get_rate API's which will do the actual scaling of the device frequency + * and retrieve the current device frequency. + * 2. Introduce use counting on a per VDD basis. This is to take care multiple + * requests to scale a VDD. The VDD will be scaled to the maximum of the + * voltages requested. + * 3. Keep track of all scalable devices belonging to a particular voltage + * domain the voltage layer. + * 4. Keep track of frequency requests for each of the device. This will enable + * to scale individual devices to different frequency (even w/o scaling + * voltage aka frequency throttling) + * 5. Generic dvfs API that can be called by anybody to scale a device opp. + * This API takes the device pointer and frequency to which the device + * needs to be scaled to. This API then internally finds out the voltage + * domain to which the device belongs to and the voltage to which the voltage + * domain needs to be put to for the device to be scaled to the new frequency + * from the device opp table. Then this API will add requested frequency into + * the corresponding target device frequency list and add voltage request to + * the corresponding vdd. Subsequently it calls voltage scale function which + * will find out the highest requested voltage for the given vdd and scales + * the voltage to the required one and also adds corresponding frequency + * request for that voltage. It also runs through the list of all + * scalable devices belonging to this voltage domain and scale them to the + * appropriate frequencies using the set_rate pointer in the device opp + * tables. + * 6. Handle inter VDD dependecies. This will take care of scaling domain's voltage + * and frequency together. + * + * + * DOC: The Core DVFS data structure: + * ================================== + * Structure Name Example Tree + * --------- + * /|\ +-------------------+ +-------------------+ + * | |User2 (dev2, freq2)+---\ |User4 (dev4, freq4)+---\ + * | +-------------------+ | +-------------------+ | + * (struct omap_dev_user_list) | | + * | +-------------------+ | +-------------------+ | + * | |User1 (dev1, freq1)+---| |User3 (dev3, freq3)+---| + * \|/ +-------------------+ | +-------------------+ | + * --------- | | + * /|\ +------------+------+ +---------------+--+ + * | | DEV1 (dev, | | DEV2 (dev) | + * (struct omap_vdd_dev_list)|omap_dev_user_list)| |omap_dev_user_list| + * | +------------+------+ +--+---------------+ + * \|/ /|\ /-----+-------------+------> others.. + * --------- Frequency | + * /|\ +--+------------------+ + * | | VDD_n | + * | | (omap_vdd_dev_list, | + * (struct omap_vdd_dvfs_info)** | omap_vdd_user_list) | + * | +--+------------------+ + * | | (ROOT NODE: omap_dvfs_info_list) + * \|/ | + * --------- Voltage \---+-------------+----------> others.. + * /|\ \|/ +-------+----+ +-----+--------+ + * | | vdd_user2 | | vdd_user3 | + * (struct omap_vdd_user_list) | (dev, volt)| | (dev, volt) | + * \|/ +------------+ +--------------+ + * --------- + * Key: ** -> Root of the tree. + * NOTE: we use the priority to store the voltage/frequency + * + * For voltage dependency description, see: struct dependency: + * voltagedomain -> (description of the voltagedomain) + * omap_vdd_info -> (vdd information) + * omap_vdd_dep_info[]-> (stores array of depedency info) + * omap_vdd_dep_volt[] -> (stores array of maps) + * (main_volt -> dep_volt) (a singular map) + */ + +/* Macros to give idea about scaling directions */ +#define DVFS_VOLT_SCALE_DOWN 0 +#define DVFS_VOLT_SCALE_NONE 1 +#define DVFS_VOLT_SCALE_UP 2 + +/** + * struct omap_dev_user_list - Structure maitain userlist per devide + * @dev: The device requesting for a particular frequency + * @node: The list head entry + * + * Using this structure, user list (requesting dev * and frequency) for + * each device is maintained. This is how we can have different devices + * at different frequencies (to support frequency locking and throttling). + * Even if one of the devices in a given vdd has locked it's frequency, + * other's can still scale their frequency using this list. + * If no one has placed a frequency request for a device, then device is + * set to the frequency from it's opp table. + */ +struct omap_dev_user_list { + struct device *dev; + struct plist_node node; +}; + +/** + * struct omap_vdd_dev_list - Device list per vdd + * @dev: The device belonging to a particular vdd + * @node: The list head entry + * @freq_user_list: The list of users for vdd device + * @clk: frequency control clock for this dev + * @user_lock: The lock for plist manipulation + */ +struct omap_vdd_dev_list { + struct device *dev; + struct list_head node; + struct plist_head freq_user_list; + struct clk *clk; + spinlock_t user_lock; /* spinlock for plist */ +}; + +/** + * struct omap_vdd_user_list - The per vdd user list + * @dev: The device asking for the vdd to be set at a particular + * voltage + * @node: The list head entry + */ +struct omap_vdd_user_list { + struct device *dev; + struct plist_node node; +}; + +/** + * struct omap_vdd_dvfs_info - The per vdd dvfs info + * @node: list node for vdd_dvfs_info list + * @user_lock: spinlock for plist operations + * @vdd_user_list: The vdd user list + * @voltdm: Voltage domains for which dvfs info stored + * @dev_list: Device list maintained per domain + * + * This is a fundamental structure used to store all the required + * DVFS related information for a vdd. + */ +struct omap_vdd_dvfs_info { + struct list_head node; + + spinlock_t user_lock; /* spin lock */ + struct plist_head vdd_user_list; + struct voltagedomain *voltdm; + struct list_head dev_list; +}; + +static LIST_HEAD(omap_dvfs_info_list); +DEFINE_MUTEX(omap_dvfs_lock); + +/* Dvfs scale helper function */ +static int _dvfs_scale(struct device *req_dev, struct device *target_dev, + struct omap_vdd_dvfs_info *tdvfs_info); + +/* Few search functions to traverse and find pointers of interest */ + +/** + * _dvfs_info_to_dev() - Locate the parent device associated to dvfs_info + * @dvfs_info: dvfs_info to search for + * + * Returns NULL on failure. + */ +static struct device *_dvfs_info_to_dev(struct omap_vdd_dvfs_info *dvfs_info) +{ + struct omap_vdd_dev_list *tmp_dev; + if (IS_ERR_OR_NULL(dvfs_info)) + return NULL; + if (list_empty(&dvfs_info->dev_list)) + return NULL; + tmp_dev = list_first_entry(&dvfs_info->dev_list, + struct omap_vdd_dev_list, node); + return tmp_dev->dev; +} + +/** + * _dev_to_dvfs_info() - Locate the dvfs_info for a device + * @dev: dev to search for + * + * Returns NULL on failure. + */ +static struct omap_vdd_dvfs_info *_dev_to_dvfs_info(struct device *dev) +{ + struct omap_vdd_dvfs_info *dvfs_info; + struct omap_vdd_dev_list *temp_dev; + + if (IS_ERR_OR_NULL(dev)) + return NULL; + + list_for_each_entry(dvfs_info, &omap_dvfs_info_list, node) { + list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { + if (temp_dev->dev == dev) + return dvfs_info; + } + } + + return NULL; +} + +/** + * _voltdm_to_dvfs_info() - Locate a dvfs_info given a voltdm pointer + * @voltdm: voltdm to search for + * + * Returns NULL on failure. + */ +static +struct omap_vdd_dvfs_info *_voltdm_to_dvfs_info(struct voltagedomain *voltdm) +{ + struct omap_vdd_dvfs_info *dvfs_info; + + if (IS_ERR_OR_NULL(voltdm)) + return NULL; + + list_for_each_entry(dvfs_info, &omap_dvfs_info_list, node) { + if (dvfs_info->voltdm == voltdm) + return dvfs_info; + } + + return NULL; +} + +/** + * _volt_to_opp() - Find OPP corresponding to a given voltage + * @dev: device pointer associated with the OPP list + * @volt: voltage to search for in uV + * + * Searches for exact match in the OPP list and returns handle to the matching + * OPP if found, else return the max available OPP. + * If there are multiple opps with same voltage, it will return + * the first available entry. Return pointer should be checked against IS_ERR. + * + * NOTE: since this uses OPP functions, use under rcu_lock. This function also + * assumes that the cpufreq table and OPP table are in sync - any modifications + * to either should be synchronized. + */ +static struct opp *_volt_to_opp(struct device *dev, unsigned long volt) +{ + struct opp *opp = ERR_PTR(-ENODEV); + unsigned long f = 0; + + do { + opp = opp_find_freq_ceil(dev, &f); + if (IS_ERR(opp)) { + /* + * if there is no OPP for corresponding volt + * then return max available instead + */ + opp = opp_find_freq_floor(dev, &f); + break; + } + if (opp_get_voltage(opp) >= volt) + break; + f++; + } while (1); + + return opp; +} + +/* rest of the helper functions */ +/** + * _add_vdd_user() - Add a voltage request + * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd + * @dev: device making the request + * @volt: requested voltage in uV + * + * Adds the given device's voltage request into corresponding + * vdd's omap_vdd_dvfs_info user list (plist). This list is used + * to find the maximum voltage request for a given vdd. + * + * Returns 0 on success. + */ +static int _add_vdd_user(struct omap_vdd_dvfs_info *dvfs_info, + struct device *dev, unsigned long volt) +{ + struct omap_vdd_user_list *user = NULL, *temp_user; + + if (!dvfs_info || IS_ERR(dvfs_info)) { + dev_warn(dev, "%s: VDD specified does not exist!\n", __func__); + return -EINVAL; + } + + spin_lock(&dvfs_info->user_lock); + plist_for_each_entry(temp_user, &dvfs_info->vdd_user_list, node) { + if (temp_user->dev == dev) { + user = temp_user; + break; + } + } + + if (!user) { + user = kzalloc(sizeof(struct omap_vdd_user_list), GFP_ATOMIC); + if (!user) { + dev_err(dev, + "%s: Unable to creat a new user for vdd_%s\n", + __func__, dvfs_info->voltdm->name); + spin_unlock(&dvfs_info->user_lock); + return -ENOMEM; + } + user->dev = dev; + } else { + plist_del(&user->node, &dvfs_info->vdd_user_list); + } + + plist_node_init(&user->node, volt); + plist_add(&user->node, &dvfs_info->vdd_user_list); + + spin_unlock(&dvfs_info->user_lock); + return 0; +} + +/** + * _remove_vdd_user() - Remove a voltage request + * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd + * @dev: device making the request + * + * Removes the given device's voltage request from corresponding + * vdd's omap_vdd_dvfs_info user list (plist). + * + * Returns 0 on success. + */ +static int _remove_vdd_user(struct omap_vdd_dvfs_info *dvfs_info, + struct device *dev) +{ + struct omap_vdd_user_list *user = NULL, *temp_user; + int ret = 0; + + if (!dvfs_info || IS_ERR(dvfs_info)) { + dev_err(dev, "%s: VDD specified does not exist!\n", __func__); + return -EINVAL; + } + + spin_lock(&dvfs_info->user_lock); + plist_for_each_entry(temp_user, &dvfs_info->vdd_user_list, node) { + if (temp_user->dev == dev) { + user = temp_user; + break; + } + } + + if (user) + plist_del(&user->node, &dvfs_info->vdd_user_list); + else { + dev_err(dev, "%s: Unable to find the user for vdd_%s\n", + __func__, dvfs_info->voltdm->name); + ret = -ENOENT; + } + + spin_unlock(&dvfs_info->user_lock); + kfree(user); + + return ret; +} + +/** + * _add_freq_request() - Add a requested device frequency + * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd + * @req_dev: device making the request + * @target_dev: target device for which frequency request is being made + * @freq: target device frequency + * + * This adds a requested frequency into target device's frequency list. + * + * Returns 0 on success. + */ +static int _add_freq_request(struct omap_vdd_dvfs_info *dvfs_info, + struct device *req_dev, struct device *target_dev, unsigned long freq) +{ + struct omap_dev_user_list *dev_user = NULL, *tmp_user; + struct omap_vdd_dev_list *temp_dev; + + if (!dvfs_info || IS_ERR(dvfs_info)) { + dev_warn(target_dev, "%s: VDD specified does not exist!\n", + __func__); + return -EINVAL; + } + + list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { + if (temp_dev->dev == target_dev) + break; + } + + if (temp_dev->dev != target_dev) { + dev_warn(target_dev, "%s: target_dev does not exist!\n", + __func__); + return -EINVAL; + } + + spin_lock(&temp_dev->user_lock); + plist_for_each_entry(tmp_user, &temp_dev->freq_user_list, node) { + if (tmp_user->dev == req_dev) { + dev_user = tmp_user; + break; + } + } + + if (!dev_user) { + dev_user = kzalloc(sizeof(struct omap_dev_user_list), + GFP_ATOMIC); + if (!dev_user) { + dev_err(target_dev, + "%s: Unable to creat a new user for vdd_%s\n", + __func__, dvfs_info->voltdm->name); + spin_unlock(&temp_dev->user_lock); + return -ENOMEM; + } + dev_user->dev = req_dev; + } else { + plist_del(&dev_user->node, &temp_dev->freq_user_list); + } + + plist_node_init(&dev_user->node, freq); + plist_add(&dev_user->node, &temp_dev->freq_user_list); + spin_unlock(&temp_dev->user_lock); + return 0; +} + +/** + * _remove_freq_request() - Remove the requested device frequency + * + * @dvfs_info: omap_vdd_dvfs_info pointer for the required vdd + * @req_dev: device removing the request + * @target_dev: target device from which frequency request is being removed + * + * This removes a requested frequency from target device's frequency list. + * + * Returns 0 on success. + */ +static int _remove_freq_request(struct omap_vdd_dvfs_info *dvfs_info, + struct device *req_dev, struct device *target_dev) +{ + struct omap_dev_user_list *dev_user = NULL, *tmp_user; + int ret = 0; + struct omap_vdd_dev_list *temp_dev; + + if (!dvfs_info || IS_ERR(dvfs_info)) { + dev_warn(target_dev, "%s: VDD specified does not exist!\n", + __func__); + return -EINVAL; + } + + + list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { + if (temp_dev->dev == target_dev) + break; + } + + if (temp_dev->dev != target_dev) { + dev_warn(target_dev, "%s: target_dev does not exist!\n", + __func__); + return -EINVAL; + } + + spin_lock(&temp_dev->user_lock); + plist_for_each_entry(tmp_user, &temp_dev->freq_user_list, node) { + if (tmp_user->dev == req_dev) { + dev_user = tmp_user; + break; + } + } + + if (dev_user) { + plist_del(&dev_user->node, &temp_dev->freq_user_list); + } else { + dev_err(target_dev, + "%s: Unable to remove the user for vdd_%s\n", + __func__, dvfs_info->voltdm->name); + ret = -EINVAL; + } + + spin_unlock(&temp_dev->user_lock); + kfree(dev_user); + + return ret; +} + +/** + * _dep_scan_table() - Scan a dependency table and mark for scaling + * @dev: device requesting the dependency scan (req_dev) + * @dep_info: dependency information (contains the table) + * @main_volt: voltage dependency to search for + * + * This runs down the table provided to find the match for main_volt + * provided and sets up a scale request for the dependent domain + * for the dependent voltage. + * + * Returns 0 if all went well. + */ +static int _dep_scan_table(struct device *dev, + struct omap_vdd_dep_info *dep_info, unsigned long main_volt) +{ + struct omap_vdd_dep_volt *dep_table = dep_info->dep_table; + struct device *target_dev; + struct omap_vdd_dvfs_info *tdvfs_info; + struct opp *opp; + int i, ret; + unsigned long dep_volt = 0, new_freq = 0; + + if (!dep_table) { + dev_err(dev, "%s: deptable not present for vdd%s\n", + __func__, dep_info->name); + return -EINVAL; + } + + /* Now scan through the the dep table for a match */ + for (i = 0; i < dep_info->nr_dep_entries; i++) { + if (dep_table[i].main_vdd_volt == main_volt) { + dep_volt = dep_table[i].dep_vdd_volt; + break; + } + } + if (!dep_volt) { + dev_warn(dev, "%s: %ld volt map missing in vdd_%s\n", + __func__, main_volt, dep_info->name); + return -EINVAL; + } + + /* populate voltdm if it is not present */ + if (!dep_info->_dep_voltdm) { + dep_info->_dep_voltdm = voltdm_lookup(dep_info->name); + if (!dep_info->_dep_voltdm) { + dev_warn(dev, "%s: unable to get vdm%s\n", + __func__, dep_info->name); + return -ENODEV; + } + } + + /* See if dep_volt is possible for the vdd*/ + ret = _add_vdd_user(_voltdm_to_dvfs_info(dep_info->_dep_voltdm), + dev, dep_volt); + if (ret) + dev_err(dev, "%s: Failed to add dep to domain %s volt=%ld\n", + __func__, dep_info->name, dep_volt); + + /* And also add corresponding freq request */ + tdvfs_info = _voltdm_to_dvfs_info(dep_info->_dep_voltdm); + if (!tdvfs_info) { + dev_warn(dev, "%s: no dvfs_info\n", + __func__); + return -ENODEV; + } + target_dev = _dvfs_info_to_dev(tdvfs_info); + if (!target_dev) { + dev_warn(dev, "%s: no target_dev\n", + __func__); + return -ENODEV; + } + + rcu_read_lock(); + opp = _volt_to_opp(target_dev, dep_volt); + if (!IS_ERR(opp)) + new_freq = opp_get_freq(opp); + rcu_read_unlock(); + + if (new_freq) { + ret = _add_freq_request(tdvfs_info, dev, target_dev, new_freq); + if (ret) { + dev_err(target_dev, "%s: freqadd(%s) failed %d[f=%ld," + "v=%ld]\n", __func__, dev_name(dev), + i, new_freq, dep_volt); + return ret; + } + } + + return ret; +} + +/** + * _dep_scan_domains() - Scan dependency domains for a device + * @dev: device requesting the scan + * @vdd: vdd_info corresponding to the device + * @main_volt: voltage to scan for + * + * Since each domain *may* have multiple dependent domains, we scan + * through each of the dependent domains and invoke _dep_scan_table to + * scan each table for dependent domain for dependency scaling. + * + * This assumes that the dependent domain information is NULL entry terminated. + * Returns 0 if all went well. + */ +static int _dep_scan_domains(struct device *dev, + struct omap_vdd_info *vdd, unsigned long main_volt) +{ + struct omap_vdd_dep_info *dep_info = vdd->dep_vdd_info; + int ret = 0, r; + + if (!dep_info) { + dev_dbg(dev, "%s: No dependent VDD\n", __func__); + return 0; + } + + /* First scan through the mydomain->dep_domain list */ + while (dep_info->nr_dep_entries) { + r = _dep_scan_table(dev, dep_info, main_volt); + /* Store last failed value */ + ret = (r) ? r : ret; + dep_info++; + } + + return ret; +} + +/** + * _dep_scale_domains() - Cause a scale of all dependent domains + * @req_dev: device requesting the scale + * @req_vdd: vdd_info corresponding to the requesting device. + * + * This walks through every dependent domain and triggers a scale + * It is assumed that the corresponding scale handling for the + * domain translates this to freq and voltage scale operations as + * needed. + * + * Note: This is uses _dvfs_scale and one should be careful not to + * create a circular depedency (e.g. vdd_mpu->vdd_core->vdd->mpu) + * which can create deadlocks. No protection is provided to prevent + * this condition and a tree organization is assumed. + * + * Returns 0 if all went fine. + */ +static int _dep_scale_domains(struct device *req_dev, + struct omap_vdd_info *req_vdd) +{ + struct omap_vdd_dep_info *dep_info = req_vdd->dep_vdd_info; + int ret = 0, r; + + if (!dep_info) { + dev_dbg(req_dev, "%s: No dependent VDD\n", __func__); + return 0; + } + + /* First scan through the mydomain->dep_domain list */ + while (dep_info->nr_dep_entries) { + struct voltagedomain *tvoltdm = dep_info->_dep_voltdm; + + r = 0; + /* Scale it only if I have a voltdm mapped up for the dep */ + if (tvoltdm) { + struct omap_vdd_dvfs_info *tdvfs_info; + struct device *target_dev; + tdvfs_info = _voltdm_to_dvfs_info(tvoltdm); + if (!tdvfs_info) { + dev_warn(req_dev, "%s: no dvfs_info\n", + __func__); + goto next; + } + target_dev = _dvfs_info_to_dev(tdvfs_info); + if (!target_dev) { + dev_warn(req_dev, "%s: no target_dev\n", + __func__); + goto next; + } + r = _dvfs_scale(req_dev, target_dev, tdvfs_info); +next: + if (r) + dev_err(req_dev, "%s: dvfs_scale to %s =%d\n", + __func__, dev_name(target_dev), r); + } + /* Store last failed value */ + ret = (r) ? r : ret; + dep_info++; + } + + return ret; +} + +/** + * _dvfs_scale() : Scale the devices associated with a voltage domain + * @req_dev: Device requesting the scale + * @target_dev: Device requesting to be scaled + * @tdvfs_info: omap_vdd_dvfs_info pointer for the target domain + * + * This runs through the list of devices associated with the + * voltage domain and scales the device rates to the one requested + * by the user or those corresponding to the new voltage of the + * voltage domain. Target voltage is the highest voltage in the vdd_user_list. + * + * Returns 0 on success else the error value. + */ +static int _dvfs_scale(struct device *req_dev, struct device *target_dev, + struct omap_vdd_dvfs_info *tdvfs_info) +{ + unsigned long curr_volt, new_volt; + int volt_scale_dir = DVFS_VOLT_SCALE_DOWN; + struct omap_vdd_dev_list *temp_dev; + struct plist_node *node; + int ret = 0; + struct voltagedomain *voltdm; + struct omap_vdd_info *vdd; + struct omap_volt_data *new_vdata; + struct omap_volt_data *curr_vdata; + + voltdm = tdvfs_info->voltdm; + if (IS_ERR_OR_NULL(voltdm)) { + dev_err(target_dev, "%s: bad voltdm\n", __func__); + return -EINVAL; + } + vdd = voltdm->vdd; + + /* Find the highest voltage being requested */ + node = plist_last(&tdvfs_info->vdd_user_list); + new_volt = node->prio; + + new_vdata = omap_voltage_get_voltdata(voltdm, new_volt); + if (IS_ERR_OR_NULL(new_vdata)) { + pr_err("%s:%s: Bad New voltage data for %ld\n", + __func__, voltdm->name, new_volt); + return PTR_ERR(new_vdata); + } + new_volt = omap_get_operation_voltage(new_vdata); + curr_vdata = omap_voltage_get_curr_vdata(voltdm); + if (IS_ERR_OR_NULL(curr_vdata)) { + pr_err("%s:%s: Bad Current voltage data\n", + __func__, voltdm->name); + return PTR_ERR(curr_vdata); + } + + /* Disable smartreflex module across voltage and frequency scaling */ + omap_sr_disable(voltdm); + + /* Pick up the current voltage ONLY after ensuring no changes occur */ + curr_volt = omap_vp_get_curr_volt(voltdm); + if (!curr_volt) + curr_volt = omap_get_operation_voltage(curr_vdata); + + /* Make a decision to scale dependent domain based on nominal voltage */ + if (omap_get_nominal_voltage(new_vdata) > + omap_get_nominal_voltage(curr_vdata)) { + ret = _dep_scale_domains(target_dev, vdd); + if (ret) { + dev_err(target_dev, + "%s: Error(%d)scale dependent with %ld volt\n", + __func__, ret, new_volt); + goto fail; + } + } + + if (voltdm->abb && omap_get_nominal_voltage(new_vdata) > + omap_get_nominal_voltage(curr_vdata)) { + ret = omap_ldo_abb_pre_scale(voltdm, new_vdata); + if (ret) { + pr_err("%s: ABB prescale failed for vdd%s: %d\n", + __func__, voltdm->name, ret); + goto fail; + } + } + + /* Now decide on switching OPP */ + if (curr_volt == new_volt) { + volt_scale_dir = DVFS_VOLT_SCALE_NONE; + } else if (curr_volt < new_volt) { + ret = voltdm_scale(voltdm, new_vdata); + if (ret) { + dev_err(target_dev, + "%s: Unable to scale the %s to %ld volt\n", + __func__, voltdm->name, new_volt); + goto fail; + } + volt_scale_dir = DVFS_VOLT_SCALE_UP; + } + + if (voltdm->abb && omap_get_nominal_voltage(new_vdata) > + omap_get_nominal_voltage(curr_vdata)) { + ret = omap_ldo_abb_post_scale(voltdm, new_vdata); + if (ret) { + pr_err("%s: ABB prescale failed for vdd%s: %d\n", + __func__, voltdm->name, ret); + goto fail; + } + } + + /* Move all devices in list to the required frequencies */ + list_for_each_entry(temp_dev, &tdvfs_info->dev_list, node) { + struct device *dev; + struct opp *opp; + unsigned long freq = 0; + int r; + + dev = temp_dev->dev; + if (!plist_head_empty(&temp_dev->freq_user_list)) { + node = plist_last(&temp_dev->freq_user_list); + freq = node->prio; + } else { + /* + * Is the dev of dep domain target_device? + * we'd probably have a voltage request without + * a frequency dependency, scale appropriate frequency + * if there are none pending + */ + if (target_dev == dev) { + rcu_read_lock(); + opp = _volt_to_opp(dev, new_volt); + if (!IS_ERR(opp)) + freq = opp_get_freq(opp); + rcu_read_unlock(); + } + if (!freq) + continue; + } + + if (freq == clk_get_rate(temp_dev->clk)) { + dev_dbg(dev, "%s: Already at the requested" + "rate %ld\n", __func__, freq); + continue; + } + + r = clk_set_rate(temp_dev->clk, freq); + if (r < 0) { + dev_err(dev, "%s: clk set rate frq=%ld failed(%d)\n", + __func__, freq, r); + ret = r; + } + } + + if (ret) + goto fail; + + if (voltdm->abb && omap_get_nominal_voltage(new_vdata) < + omap_get_nominal_voltage(curr_vdata)) { + ret = omap_ldo_abb_pre_scale(voltdm, new_vdata); + if (ret) { + pr_err("%s: ABB prescale failed for vdd%s: %d\n", + __func__, voltdm->name, ret); + goto fail; + } + } + + if (DVFS_VOLT_SCALE_DOWN == volt_scale_dir) + voltdm_scale(voltdm, new_vdata); + + if (voltdm->abb && omap_get_nominal_voltage(new_vdata) < + omap_get_nominal_voltage(curr_vdata)) { + ret = omap_ldo_abb_post_scale(voltdm, new_vdata); + if (ret) + pr_err("%s: ABB postscale failed for vdd%s: %d\n", + __func__, voltdm->name, ret); + } + + /* Make a decision to scale dependent domain based on nominal voltage */ + if (omap_get_nominal_voltage(new_vdata) < + omap_get_nominal_voltage(curr_vdata)) { + _dep_scale_domains(target_dev, vdd); + } + + /* Ensure that current voltage data pointer points to new volt */ + if (curr_volt == new_volt && omap_get_nominal_voltage(new_vdata) != + omap_get_nominal_voltage(curr_vdata)) { + voltdm->curr_volt = new_vdata; + omap_vp_update_errorgain(voltdm, new_vdata); + } + + /* All clear.. go out gracefully */ + goto out; + +fail: + pr_warning("%s: domain%s: No clean recovery available! could be bad!\n", + __func__, voltdm->name); +out: + /* Re-enable Smartreflex module */ + omap_sr_enable(voltdm, new_vdata); + + return ret; +} + +/* Public functions */ + +/** + * omap_device_scale() - Set a new rate at which the device is to operate + * @req_dev: pointer to the device requesting the scaling. + * @target_dev: pointer to the device that is to be scaled + * @rate: the rnew rate for the device. + * + * This API gets the device opp table associated with this device and + * tries putting the device to the requested rate and the voltage domain + * associated with the device to the voltage corresponding to the + * requested rate. Since multiple devices can be assocciated with a + * voltage domain this API finds out the possible voltage the + * voltage domain can enter and then decides on the final device + * rate. + * + * Return 0 on success else the error value + */ +int omap_device_scale(struct device *req_dev, struct device *target_dev, + unsigned long rate) +{ + struct opp *opp; + unsigned long volt, freq = rate, new_freq = 0; + struct omap_vdd_dvfs_info *tdvfs_info; + struct platform_device *pdev; + struct omap_device *od; + struct device *dev; + int ret = 0; + + pdev = container_of(target_dev, struct platform_device, dev); + if (IS_ERR_OR_NULL(pdev)) { + pr_err("%s: pdev is null!\n", __func__); + return -EINVAL; + } + + od = container_of(pdev, struct omap_device, pdev); + if (IS_ERR_OR_NULL(od)) { + pr_err("%s: od is null!\n", __func__); + return -EINVAL; + } + + if (!omap_pm_is_ready()) { + dev_dbg(target_dev, "%s: pm is not ready yet\n", __func__); + return -EBUSY; + } + + /* Lock me to ensure cross domain scaling is secure */ + mutex_lock(&omap_dvfs_lock); + + rcu_read_lock(); + opp = opp_find_freq_ceil(target_dev, &freq); + /* If we dont find a max, try a floor at least */ + if (IS_ERR(opp)) + opp = opp_find_freq_floor(target_dev, &freq); + if (IS_ERR(opp)) { + rcu_read_unlock(); + dev_err(target_dev, "%s: Unable to find OPP for freq%ld\n", + __func__, rate); + ret = -ENODEV; + goto out; + } + volt = opp_get_voltage(opp); + rcu_read_unlock(); + + tdvfs_info = _dev_to_dvfs_info(target_dev); + if (IS_ERR_OR_NULL(tdvfs_info)) { + dev_err(target_dev, "%s: (req=%s) no vdd![f=%ld, v=%ld]\n", + __func__, dev_name(req_dev), freq, volt); + ret = -ENODEV; + goto out; + } + + ret = _add_freq_request(tdvfs_info, req_dev, target_dev, freq); + if (ret) { + dev_err(target_dev, "%s: freqadd(%s) failed %d[f=%ld, v=%ld]\n", + __func__, dev_name(req_dev), ret, freq, volt); + goto out; + } + + ret = _add_vdd_user(tdvfs_info, req_dev, volt); + if (ret) { + dev_err(target_dev, "%s: vddadd(%s) failed %d[f=%ld, v=%ld]\n", + __func__, dev_name(req_dev), ret, freq, volt); + _remove_freq_request(tdvfs_info, req_dev, + target_dev); + goto out; + } + + /* Check for any dep domains and add the user request */ + ret = _dep_scan_domains(target_dev, tdvfs_info->voltdm->vdd, volt); + if (ret) { + dev_err(target_dev, + "%s: Error in scan domains for vdd_%s\n", + __func__, tdvfs_info->voltdm->name); + goto out; + } + + dev = _dvfs_info_to_dev(tdvfs_info); + if (!dev) { + dev_warn(dev, "%s: no target_dev\n", + __func__); + ret = -ENODEV; + goto out; + } + + if (dev != target_dev) { + rcu_read_lock(); + opp = _volt_to_opp(dev, volt); + if (!IS_ERR(opp)) + new_freq = opp_get_freq(opp); + rcu_read_unlock(); + if (new_freq) { + ret = _add_freq_request(tdvfs_info, req_dev, dev, + new_freq); + if (ret) { + dev_err(target_dev, "%s: freqadd(%s) failed %d" + "[f=%ld, v=%ld]\n", __func__, + dev_name(req_dev), ret, freq, volt); + goto out; + } + } + } + + /* Do the actual scaling */ + ret = _dvfs_scale(req_dev, target_dev, tdvfs_info); + if (ret) { + dev_err(target_dev, "%s: scale by %s failed %d[f=%ld, v=%ld]\n", + __func__, dev_name(req_dev), ret, freq, volt); + _remove_freq_request(tdvfs_info, req_dev, + target_dev); + _remove_vdd_user(tdvfs_info, target_dev); + /* Fall through */ + } + /* Fall through */ +out: + mutex_unlock(&omap_dvfs_lock); + return ret; +} +EXPORT_SYMBOL(omap_device_scale); + +#ifdef CONFIG_PM_DEBUG +static int dvfs_dump_vdd(struct seq_file *sf, void *unused) +{ + int k; + struct omap_vdd_dvfs_info *dvfs_info; + struct omap_vdd_dev_list *tdev; + struct omap_dev_user_list *duser; + struct omap_vdd_user_list *vuser; + struct omap_vdd_info *vdd; + struct omap_vdd_dep_info *dep_info; + struct voltagedomain *voltdm; + struct omap_volt_data *volt_data; + int anyreq; + int anyreq2; + + dvfs_info = (struct omap_vdd_dvfs_info *)sf->private; + if (IS_ERR_OR_NULL(dvfs_info)) { + pr_err("%s: NO DVFS?\n", __func__); + return -EINVAL; + } + + voltdm = dvfs_info->voltdm; + if (IS_ERR_OR_NULL(voltdm)) { + pr_err("%s: NO voltdm?\n", __func__); + return -EINVAL; + } + + vdd = voltdm->vdd; + if (IS_ERR_OR_NULL(vdd)) { + pr_err("%s: NO vdd data?\n", __func__); + return -EINVAL; + } + + seq_printf(sf, "vdd_%s\n", voltdm->name); + mutex_lock(&omap_dvfs_lock); + spin_lock(&dvfs_info->user_lock); + + seq_printf(sf, "|- voltage requests\n| |\n"); + anyreq = 0; + plist_for_each_entry(vuser, &dvfs_info->vdd_user_list, node) { + seq_printf(sf, "| |-%d: %s:%s\n", + vuser->node.prio, + dev_driver_string(vuser->dev), dev_name(vuser->dev)); + anyreq = 1; + } + + spin_unlock(&dvfs_info->user_lock); + + if (!anyreq) + seq_printf(sf, "| `-none\n"); + else + seq_printf(sf, "| X\n"); + seq_printf(sf, "|\n"); + + seq_printf(sf, "|- frequency requests\n| |\n"); + anyreq2 = 0; + list_for_each_entry(tdev, &dvfs_info->dev_list, node) { + anyreq = 0; + seq_printf(sf, "| |- %s:%s\n", + dev_driver_string(tdev->dev), dev_name(tdev->dev)); + spin_lock(&tdev->user_lock); + plist_for_each_entry(duser, &tdev->freq_user_list, node) { + seq_printf(sf, "| | |-%d: %s:%s\n", + duser->node.prio, + dev_driver_string(duser->dev), + dev_name(duser->dev)); + anyreq = 1; + } + + spin_unlock(&tdev->user_lock); + + if (!anyreq) + seq_printf(sf, "| | `-none\n"); + else + seq_printf(sf, "| | X\n"); + anyreq2 = 1; + } + if (!anyreq2) + seq_printf(sf, "| `-none\n"); + else + seq_printf(sf, "| X\n"); + + volt_data = vdd->volt_data; + seq_printf(sf, "|- Supported voltages\n| |\n"); + anyreq = 0; + while (volt_data && volt_data->volt_nominal) { + seq_printf(sf, "| |-%d\n", volt_data->volt_nominal); + anyreq = 1; + volt_data++; + } + if (!anyreq) + seq_printf(sf, "| `-none\n"); + else + seq_printf(sf, "| X\n"); + + dep_info = vdd->dep_vdd_info; + seq_printf(sf, "`- voltage dependencies\n |\n"); + anyreq = 0; + while (dep_info && dep_info->nr_dep_entries) { + struct omap_vdd_dep_volt *dep_table = dep_info->dep_table; + + seq_printf(sf, " |-on vdd_%s\n", dep_info->name); + + for (k = 0; k < dep_info->nr_dep_entries; k++) { + seq_printf(sf, " | |- %d => %d\n", + dep_table[k].main_vdd_volt, + dep_table[k].dep_vdd_volt); + } + + anyreq = 1; + dep_info++; + } + + if (!anyreq) + seq_printf(sf, " `- none\n"); + else + seq_printf(sf, " X X\n"); + + mutex_unlock(&omap_dvfs_lock); + return 0; +} + +static int dvfs_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, dvfs_dump_vdd, inode->i_private); +} + +static struct file_operations debugdvfs_fops = { + .open = dvfs_dbg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry __initdata *dvfsdebugfs_dir; + +static void __init dvfs_dbg_init(struct omap_vdd_dvfs_info *dvfs_info) +{ + struct dentry *ddir; + + /* create a base dir */ + if (!dvfsdebugfs_dir) + dvfsdebugfs_dir = debugfs_create_dir("dvfs", NULL); + if (IS_ERR_OR_NULL(dvfsdebugfs_dir)) { + WARN_ONCE("%s: Unable to create base DVFS dir\n", __func__); + return; + } + + if (IS_ERR_OR_NULL(dvfs_info->voltdm)) { + pr_err("%s: no voltdm\n", __func__); + return; + } + + ddir = debugfs_create_dir(dvfs_info->voltdm->name, dvfsdebugfs_dir); + if (IS_ERR_OR_NULL(ddir)) { + pr_warning("%s: unable to create subdir %s\n", __func__, + dvfs_info->voltdm->name); + return; + } + + debugfs_create_file("info", S_IRUGO, ddir, + (void *)dvfs_info, &debugdvfs_fops); +} +#else /* CONFIG_PM_DEBUG */ +static inline void dvfs_dbg_init(struct omap_vdd_dvfs_info *dvfs_info) +{ + return; +} +#endif /* CONFIG_PM_DEBUG */ + +/** + * omap_dvfs_register_device - Add a parent device into dvfs managed list + * @dev: Device to be added + * @voltdm_name: Name of the voltage domain for the device + * @clk_name: Name of the clock for the device + * + * This function adds a given device into user_list of corresponding + * vdd's omap_vdd_dvfs_info strucure. This list is traversed to scale + * frequencies of all the devices on a given vdd. + * + * Returns 0 on success. + */ +int __init omap_dvfs_register_device(struct device *dev, char *voltdm_name, + char *clk_name) +{ + struct omap_vdd_dev_list *temp_dev; + struct omap_vdd_dvfs_info *dvfs_info; + struct clk *clk = NULL; + struct voltagedomain *voltdm; + int ret = 0; + + if (!voltdm_name) { + dev_err(dev, "%s: Bad voltdm name!\n", __func__); + return -EINVAL; + } + if (!clk_name) { + dev_err(dev, "%s: Bad clk name!\n", __func__); + return -EINVAL; + } + + /* Lock me to secure structure changes */ + mutex_lock(&omap_dvfs_lock); + + voltdm = voltdm_lookup(voltdm_name); + if (!voltdm) { + dev_warn(dev, "%s: unable to find voltdm %s!\n", + __func__, voltdm_name); + ret = -EINVAL; + goto out; + } + dvfs_info = _voltdm_to_dvfs_info(voltdm); + if (!dvfs_info) { + dvfs_info = kzalloc(sizeof(struct omap_vdd_dvfs_info), + GFP_KERNEL); + if (!dvfs_info) { + dev_warn(dev, "%s: unable to alloc memory!\n", + __func__); + ret = -ENOMEM; + goto out; + } + dvfs_info->voltdm = voltdm; + + /* Init the plist */ + spin_lock_init(&dvfs_info->user_lock); + plist_head_init(&dvfs_info->vdd_user_list); + /* Init the device list */ + INIT_LIST_HEAD(&dvfs_info->dev_list); + + list_add(&dvfs_info->node, &omap_dvfs_info_list); + + dvfs_dbg_init(dvfs_info); + } + + /* If device already added, we dont need to do more.. */ + list_for_each_entry(temp_dev, &dvfs_info->dev_list, node) { + if (temp_dev->dev == dev) + goto out; + } + + temp_dev = kzalloc(sizeof(struct omap_vdd_dev_list), GFP_KERNEL); + if (!temp_dev) { + dev_err(dev, "%s: Unable to creat a new device for vdd_%s\n", + __func__, dvfs_info->voltdm->name); + ret = -ENOMEM; + goto out; + } + + clk = clk_get(dev, clk_name); + if (IS_ERR_OR_NULL(clk)) { + dev_warn(dev, "%s: Bad clk pointer!\n", __func__); + kfree(temp_dev); + ret = -EINVAL; + goto out; + } + + /* Initialize priority ordered list */ + spin_lock_init(&temp_dev->user_lock); + plist_head_init(&temp_dev->freq_user_list); + + temp_dev->dev = dev; + temp_dev->clk = clk; + list_add_tail(&temp_dev->node, &dvfs_info->dev_list); + + /* Fall through */ +out: + mutex_unlock(&omap_dvfs_lock); + return ret; +} diff --git a/arch/arm/mach-omap2/dvfs.h b/arch/arm/mach-omap2/dvfs.h new file mode 100644 index 0000000..b0a0cd6 --- /dev/null +++ b/arch/arm/mach-omap2/dvfs.h @@ -0,0 +1,47 @@ +/* + * OMAP3/OMAP4 DVFS Management Routines + * + * Author: Vishwanath BS <vishwanath.bs@ti.com> + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Vishwanath BS <vishwanath.bs@ti.com> + * + * 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. + */ + +#ifndef __ARCH_ARM_MACH_OMAP2_DVFS_H +#define __ARCH_ARM_MACH_OMAP2_DVFS_H +#include <plat/omap_hwmod.h> +#include "voltage.h" + +#ifdef CONFIG_PM +#include <linux/mutex.h> +extern struct mutex omap_dvfs_lock; +int omap_dvfs_register_device(struct device *dev, char *voltdm_name, + char *clk_name); +int omap_device_scale(struct device *req_dev, struct device *target_dev, + unsigned long rate); + +static inline bool omap_dvfs_is_any_dev_scaling(void) +{ + return mutex_is_locked(&omap_dvfs_lock); +} +#else +static inline int omap_dvfs_register_device(struct device *dev, + char *voltdm_name, char *clk_name) +{ + return -EINVAL; +} +static inline int omap_device_scale(struct device *req_dev, + struct device *target_dev, unsigned long rate) +{ + return -EINVAL; +} +static inline bool omap_dvfs_is_any_dev_scaling(void) +{ + return false; +} +#endif +#endif diff --git a/arch/arm/mach-omap2/emif.c b/arch/arm/mach-omap2/emif.c new file mode 100644 index 0000000..8f4ec5f --- /dev/null +++ b/arch/arm/mach-omap2/emif.c @@ -0,0 +1,1514 @@ +/* + * OMAP4 EMIF platform driver + * + * Copyright (C) 2010 Texas Instruments, Inc. + * + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * Aneesh V <aneesh@ti.com> + * Vibhore Vardhan <vvardhan@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <plat/omap_hwmod.h> +#include <plat/omap_device.h> +#include <mach/emif-44xx.h> +#include <mach/emif.h> +#include <mach/lpddr2-jedec.h> +#include <mach/omap4-common.h> + +#include "voltage.h" + +/* Utility macro for masking and setting a field in a register/variable */ +#define mask_n_set(reg, shift, msk, val) \ + (reg) = (((reg) & ~(msk))|(((val) << (shift)) & msk)) + +struct emif_instance { + void __iomem *base; + u16 irq; + struct platform_device *pdev; + bool ddr_refresh_disabled; +}; +static struct emif_instance emif[EMIF_NUM_INSTANCES]; +static struct emif_regs *emif_curr_regs[EMIF_NUM_INSTANCES]; +static struct emif_regs *emif1_regs_cache[EMIF_MAX_NUM_FREQUENCIES]; +static struct emif_regs *emif2_regs_cache[EMIF_MAX_NUM_FREQUENCIES]; +static struct emif_device_details *emif_devices[2]; +static u32 emif_temperature_level[EMIF_NUM_INSTANCES] = { SDRAM_TEMP_NOMINAL, + SDRAM_TEMP_NOMINAL +}; + +static u32 emif_notify_pending; +static u32 emif_thermal_handling_pending; +static u32 T_den, T_num; + +static struct omap_device_pm_latency omap_emif_latency[] = { + [0] = { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +static void do_cancel_out(u32 *num, u32 *den, u32 factor) +{ + while (1) { + if (((*num) / factor * factor == (*num)) && + ((*den) / factor * factor == (*den))) { + (*num) /= factor; + (*den) /= factor; + } else + break; + } +} + +static void cancel_out(u32 *num, u32 *den) +{ + do_cancel_out(num, den, 2); + do_cancel_out(num, den, 3); + do_cancel_out(num, den, 5); + do_cancel_out(num, den, 7); + do_cancel_out(num, den, 11); + do_cancel_out(num, den, 13); + do_cancel_out(num, den, 17); +} + +/* + * Get the period in ns (in fraction form) for a given frequency: + * Getting it in fraction form is for better accuracy in integer arithmetics + * freq_hz - input: frequency in Hertz + * den_limit - input: upper limit for denominator. see the description of + * EMIF_PERIOD_DEN_LIMIT for more details + * period_den - output: pointer to denominator of period in ns + * period_num - output: pointer to numerator of period in ns + */ +static void get_period(u32 freq_hz, u32 den_limit, u32 *period_num, + u32 *period_den) +{ + *period_num = 1000000000; /* 10^9 to convert the period to 'ns' */ + *period_den = freq_hz; + cancel_out(period_num, period_den); + /* make sure den <= den_limit at the cost of some accuracy */ + while ((*period_den) > den_limit) { + *period_num /= 2; + *period_den /= 2; + } +} + +/* + * Calculate the period of DDR clock from frequency value and set the + * denominator and numerator in global variables for easy access later + */ +static void set_ddr_clk_period(u32 freq) +{ + get_period(freq, EMIF_PERIOD_DEN_LIMIT, &T_num, &T_den); +} + +/* + * Convert time in nano seconds to number of cycles of DDR clock + */ +static u32 ns_2_cycles(u32 ns) +{ + return ((ns * T_den) + T_num - 1) / T_num; +} + +/* + * ns_2_cycles with the difference that the time passed is 2 times the actual + * value(to avoid fractions). The cycles returned is for the original value of + * the timing parameter + */ +static u32 ns_x2_2_cycles(u32 ns) +{ + return ((ns * T_den) + T_num * 2 - 1) / (T_num * 2); +} + +/* + * Find addressing table index based on the device's type(S2 or S4) and + * density + */ +static s8 addressing_table_index(u8 type, u8 density, u8 width) +{ + u8 index; + if (unlikely((density > LPDDR2_DENSITY_8Gb) || + (width == LPDDR2_IO_WIDTH_8))) + return -1; + + /* + * Look at the way ADDR_TABLE_INDEX* values have been defined + * in emif.h compared to LPDDR2_DENSITY_* values + * The table is layed out in the increasing order of density + * (ignoring type). The exceptions 1GS2 and 2GS2 have been placed + * at the end + */ + if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_1Gb)) + index = ADDR_TABLE_INDEX1GS2; + else if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_2Gb)) + index = ADDR_TABLE_INDEX2GS2; + else + index = density; + + pr_debug("emif: addressing table index %d", index); + + return index; +} + +/* + * Find the the right timing table from the array of timing + * tables of the device using DDR clock frequency + */ +static const struct lpddr2_timings *get_timings_table( + const struct lpddr2_timings * const *device_timings, u32 freq) +{ + u32 i, temp, freq_nearest; + const struct lpddr2_timings *timings = NULL; + + emif_assert(freq <= MAX_LPDDR2_FREQ); + emif_assert(device_timings); + + /* + * Start with the maximum allowed frequency - that is always safe + */ + freq_nearest = MAX_LPDDR2_FREQ; + /* + * Find the timings table that has the max frequency value: + * i. Above or equal to the DDR frequency - safe + * ii. The lowest that satisfies condition (i) - optimal + */ + for (i = 0; i < MAX_NUM_SPEEDBINS; i++) { + if (device_timings[i]) { + temp = device_timings[i]->max_freq; + if ((temp >= freq) && (temp <= freq_nearest)) { + freq_nearest = temp; + timings = device_timings[i]; + } + } + } + pr_debug("emif: timings table: %d", freq_nearest); + return timings; +} + +/* + * Finds the value of emif_sdram_config_reg + * All parameters are programmed based on the device on CS0. + * If there is a device on CS1, it will be same as that on CS0 or + * it will be NVM. We don't support NVM yet. + * If cs1_device pointer is NULL it is assumed that there is no device + * on CS1 + */ +static u32 get_sdram_config_reg(const struct lpddr2_device_info *cs0_device, + const struct lpddr2_device_info *cs1_device, + const struct lpddr2_addressing *addressing, + u8 RL) +{ + u32 config_reg = 0; + + mask_n_set(config_reg, OMAP44XX_REG_SDRAM_TYPE_SHIFT, + OMAP44XX_REG_SDRAM_TYPE_MASK, cs0_device->type + 4); + + mask_n_set(config_reg, OMAP44XX_REG_IBANK_POS_SHIFT, + OMAP44XX_REG_IBANK_POS_MASK, + EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING); + + mask_n_set(config_reg, OMAP44XX_REG_NARROW_MODE_SHIFT, + OMAP44XX_REG_NARROW_MODE_MASK, cs0_device->io_width); + + mask_n_set(config_reg, OMAP44XX_REG_CL_SHIFT, OMAP44XX_REG_CL_MASK, RL); + + mask_n_set(config_reg, OMAP44XX_REG_ROWSIZE_SHIFT, + OMAP44XX_REG_ROWSIZE_MASK, + addressing->row_sz[cs0_device->io_width]); + + mask_n_set(config_reg, OMAP44XX_REG_IBANK_SHIFT, + OMAP44XX_REG_IBANK_MASK, addressing->num_banks); + + mask_n_set(config_reg, OMAP44XX_REG_EBANK_SHIFT, + OMAP44XX_REG_EBANK_MASK, + (cs1_device ? EBANK_CS1_EN : EBANK_CS1_DIS)); + + mask_n_set(config_reg, OMAP44XX_REG_PAGESIZE_SHIFT, + OMAP44XX_REG_PAGESIZE_MASK, + addressing->col_sz[cs0_device->io_width]); + + return config_reg; +} + +static u32 get_sdram_ref_ctrl(u32 freq, + const struct lpddr2_addressing *addressing) +{ + u32 ref_ctrl = 0, val = 0, freq_khz; + freq_khz = freq / 1000; + /* + * refresh rate to be set is 'tREFI * freq in MHz + * division by 10000 to account for khz and x10 in t_REFI_us_x10 + */ + val = addressing->t_REFI_us_x10 * freq_khz / 10000; + mask_n_set(ref_ctrl, OMAP44XX_REG_REFRESH_RATE_SHIFT, + OMAP44XX_REG_REFRESH_RATE_MASK, val); + + /* enable refresh */ + mask_n_set(ref_ctrl, OMAP44XX_REG_INITREF_DIS_SHIFT, + OMAP44XX_REG_INITREF_DIS_MASK, 1); + return ref_ctrl; +} + +static u32 get_sdram_tim_1_reg(const struct lpddr2_timings *timings, + const struct lpddr2_min_tck *min_tck, + const struct lpddr2_addressing *addressing) +{ + u32 tim1 = 0, val = 0; + val = max(min_tck->tWTR, ns_x2_2_cycles(timings->tWTRx2)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_WTR_SHIFT, OMAP44XX_REG_T_WTR_MASK, + val); + + if (addressing->num_banks == BANKS8) + val = (timings->tFAW * T_den + 4 * T_num - 1) / (4 * T_num) - 1; + else + val = max(min_tck->tRRD, ns_2_cycles(timings->tRRD)) - 1; + + mask_n_set(tim1, OMAP44XX_REG_T_RRD_SHIFT, OMAP44XX_REG_T_RRD_MASK, + val); + + val = ns_2_cycles(timings->tRASmin + timings->tRPab) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_RC_SHIFT, OMAP44XX_REG_T_RC_MASK, val); + + val = max(min_tck->tRAS_MIN, ns_2_cycles(timings->tRASmin)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_RAS_SHIFT, OMAP44XX_REG_T_RAS_MASK, + val); + + val = max(min_tck->tWR, ns_2_cycles(timings->tWR)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_WR_SHIFT, OMAP44XX_REG_T_WR_MASK, val); + + val = max(min_tck->tRCD, ns_2_cycles(timings->tRCD)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_RCD_SHIFT, OMAP44XX_REG_T_RCD_MASK, + val); + val = max(min_tck->tRP_AB, ns_2_cycles(timings->tRPab)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_RP_SHIFT, OMAP44XX_REG_T_RP_MASK, val); + + return tim1; +} + +/* + * Finds the de-rated value for EMIF_SDRAM_TIM1 register + * All the de-rated timings are limited to this register + * Adds 2ns instead of 1.875ns to the affected timings as + * we can not use float. + */ +static u32 get_sdram_tim_1_reg_derated(const struct lpddr2_timings *timings, + const struct lpddr2_min_tck *min_tck, + const struct lpddr2_addressing + *addressing) +{ + u32 tim1 = 0, val = 0; + val = max(min_tck->tWTR, ns_x2_2_cycles(timings->tWTRx2)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_WTR_SHIFT, OMAP44XX_REG_T_WTR_MASK, + val); + + if (addressing->num_banks == BANKS8) + /* + * tFAW is approximately 4 times tRRD. So add 1.875*4 = 7.5 ~ 8 + * to tFAW for de-rating + */ + val = ((timings->tFAW + 8) * T_den + 4 * T_num - 1) + / (4 * T_num) - 1; + else + val = max(min_tck->tRRD, ns_2_cycles(timings->tRRD + 2)) - 1; + + mask_n_set(tim1, OMAP44XX_REG_T_RRD_SHIFT, OMAP44XX_REG_T_RRD_MASK, + val); + + val = ns_2_cycles(timings->tRASmin + timings->tRPab + 2) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_RC_SHIFT, OMAP44XX_REG_T_RC_MASK, val); + + val = max(min_tck->tRAS_MIN, ns_2_cycles(timings->tRASmin + 2)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_RAS_SHIFT, OMAP44XX_REG_T_RAS_MASK, + val); + + val = max(min_tck->tWR, ns_2_cycles(timings->tWR)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_WR_SHIFT, OMAP44XX_REG_T_WR_MASK, val); + + val = max(min_tck->tRCD, ns_2_cycles(timings->tRCD + 2)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_RCD_SHIFT, OMAP44XX_REG_T_RCD_MASK, + val); + val = max(min_tck->tRP_AB, ns_2_cycles(timings->tRPab + 2)) - 1; + mask_n_set(tim1, OMAP44XX_REG_T_RP_SHIFT, OMAP44XX_REG_T_RP_MASK, val); + + return tim1; +} + +static u32 get_sdram_tim_2_reg(const struct lpddr2_timings *timings, + const struct lpddr2_min_tck *min_tck) +{ + u32 tim2 = 0, val = 0; + val = max(min_tck->tCKE, timings->tCKE) - 1; + mask_n_set(tim2, OMAP44XX_REG_T_CKE_SHIFT, OMAP44XX_REG_T_CKE_MASK, + val); + + val = max(min_tck->tRTP, ns_x2_2_cycles(timings->tRTPx2)) - 1; + mask_n_set(tim2, OMAP44XX_REG_T_RTP_SHIFT, OMAP44XX_REG_T_RTP_MASK, + val); + + /* + * tXSRD = tRFCab + 10 ns. XSRD and XSNR should have the + * same value + */ + val = ns_2_cycles(timings->tXSR) - 1; + mask_n_set(tim2, OMAP44XX_REG_T_XSRD_SHIFT, OMAP44XX_REG_T_XSRD_MASK, + val); + mask_n_set(tim2, OMAP44XX_REG_T_XSNR_SHIFT, OMAP44XX_REG_T_XSNR_MASK, + val); + + val = max(min_tck->tXP, ns_x2_2_cycles(timings->tXPx2)) - 1; + mask_n_set(tim2, OMAP44XX_REG_T_XP_SHIFT, OMAP44XX_REG_T_XP_MASK, val); + + return tim2; +} + +static u32 get_sdram_tim_3_reg(const struct lpddr2_timings *timings, + const struct lpddr2_min_tck *min_tck, + const struct lpddr2_addressing *addressing) +{ + u32 tim3 = 0, val = 0; + val = min(timings->tRASmax * 10 / addressing->t_REFI_us_x10 - 1, 0xF); + mask_n_set(tim3, OMAP44XX_REG_T_RAS_MAX_SHIFT, + OMAP44XX_REG_T_RAS_MAX_MASK, val); + + val = ns_2_cycles(timings->tRFCab) - 1; + mask_n_set(tim3, OMAP44XX_REG_T_RFC_SHIFT, OMAP44XX_REG_T_RFC_MASK, + val); + + val = ns_x2_2_cycles(timings->tDQSCKMAXx2) - 1; + mask_n_set(tim3, OMAP44XX_REG_T_TDQSCKMAX_SHIFT, + OMAP44XX_REG_T_TDQSCKMAX_MASK, val); + + val = ns_2_cycles(timings->tZQCS) - 1; + mask_n_set(tim3, OMAP44XX_REG_ZQ_ZQCS_SHIFT, + OMAP44XX_REG_ZQ_ZQCS_MASK, val); + + val = max(min_tck->tCKESR, ns_2_cycles(timings->tCKESR)) - 1; + mask_n_set(tim3, OMAP44XX_REG_T_CKESR_SHIFT, + OMAP44XX_REG_T_CKESR_MASK, val); + + return tim3; +} + +static u32 get_zq_config_reg(const struct lpddr2_device_info *cs1_device, + const struct lpddr2_addressing *addressing, + bool volt_ramp) +{ + u32 zq = 0, val = 0; + if (volt_ramp) + val = + EMIF_ZQCS_INTERVAL_DVFS_IN_US * 10 / + addressing->t_REFI_us_x10; + else + val = + EMIF_ZQCS_INTERVAL_NORMAL_IN_US * 10 / + addressing->t_REFI_us_x10; + mask_n_set(zq, OMAP44XX_REG_ZQ_REFINTERVAL_SHIFT, + OMAP44XX_REG_ZQ_REFINTERVAL_MASK, val); + + mask_n_set(zq, OMAP44XX_REG_ZQ_ZQCL_MULT_SHIFT, + OMAP44XX_REG_ZQ_ZQCL_MULT_MASK, REG_ZQ_ZQCL_MULT - 1); + + mask_n_set(zq, OMAP44XX_REG_ZQ_ZQINIT_MULT_SHIFT, + OMAP44XX_REG_ZQ_ZQINIT_MULT_MASK, REG_ZQ_ZQINIT_MULT - 1); + + mask_n_set(zq, OMAP44XX_REG_ZQ_SFEXITEN_SHIFT, + OMAP44XX_REG_ZQ_SFEXITEN_MASK, REG_ZQ_SFEXITEN_ENABLE); + + /* + * Assuming that two chipselects have a single calibration resistor + * If there are indeed two calibration resistors, then this flag should + * be enabled to take advantage of dual calibration feature. + * This data should ideally come from board files. But considering + * that none of the boards today have calibration resistors per CS, + * it would be an unnecessary overhead. + */ + mask_n_set(zq, OMAP44XX_REG_ZQ_DUALCALEN_SHIFT, + OMAP44XX_REG_ZQ_DUALCALEN_MASK, REG_ZQ_DUALCALEN_DISABLE); + + mask_n_set(zq, OMAP44XX_REG_ZQ_CS0EN_SHIFT, + OMAP44XX_REG_ZQ_CS0EN_MASK, REG_ZQ_CS0EN_ENABLE); + + mask_n_set(zq, OMAP44XX_REG_ZQ_CS1EN_SHIFT, + OMAP44XX_REG_ZQ_CS1EN_MASK, (cs1_device ? 1 : 0)); + + return zq; +} + +static u32 get_temp_alert_config(const struct lpddr2_device_info *cs1_device, + const struct lpddr2_addressing *addressing, + bool is_derated) +{ + u32 alert = 0, interval; + interval = + TEMP_ALERT_POLL_INTERVAL_MS * 10000 / addressing->t_REFI_us_x10; + if (is_derated) + interval *= 4; + mask_n_set(alert, OMAP44XX_REG_TA_REFINTERVAL_SHIFT, + OMAP44XX_REG_TA_REFINTERVAL_MASK, interval); + + mask_n_set(alert, OMAP44XX_REG_TA_DEVCNT_SHIFT, + OMAP44XX_REG_TA_DEVCNT_MASK, TEMP_ALERT_CONFIG_DEVCT_1); + + mask_n_set(alert, OMAP44XX_REG_TA_DEVWDT_SHIFT, + OMAP44XX_REG_TA_DEVWDT_MASK, TEMP_ALERT_CONFIG_DEVWDT_32); + + mask_n_set(alert, OMAP44XX_REG_TA_SFEXITEN_SHIFT, + OMAP44XX_REG_TA_SFEXITEN_MASK, 1); + + mask_n_set(alert, OMAP44XX_REG_TA_CS0EN_SHIFT, + OMAP44XX_REG_TA_CS0EN_MASK, 1); + + mask_n_set(alert, OMAP44XX_REG_TA_CS1EN_SHIFT, + OMAP44XX_REG_TA_CS1EN_MASK, (cs1_device ? 1 : 0)); + + return alert; +} + +static u32 get_read_idle_ctrl_reg(bool volt_ramp) +{ + u32 idle = 0, val = 0; + if (volt_ramp) + val = ns_2_cycles(READ_IDLE_INTERVAL_DVFS) / 64 - 1; + else + /*Maximum value in normal conditions - suggested by hw team */ + val = 0x1FF; + mask_n_set(idle, OMAP44XX_REG_READ_IDLE_INTERVAL_SHIFT, + OMAP44XX_REG_READ_IDLE_INTERVAL_MASK, val); + + mask_n_set(idle, OMAP44XX_REG_READ_IDLE_LEN_SHIFT, + OMAP44XX_REG_READ_IDLE_LEN_MASK, EMIF_REG_READ_IDLE_LEN_VAL); + + return idle; +} + +static u32 get_ddr_phy_ctrl_1(u32 freq, u8 RL) +{ + u32 phy = 0, val = 0; + + mask_n_set(phy, OMAP44XX_REG_READ_LATENCY_SHIFT, + OMAP44XX_REG_READ_LATENCY_MASK, RL + 2); + + if (freq <= 100000000) + val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS; + else if (freq <= 200000000) + val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ; + else + val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ; + mask_n_set(phy, OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHIFT, + OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_MASK, val); + + /* Other fields are constant magic values. Hardcode them together */ + mask_n_set(phy, OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHIFT, + OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_MASK, + EMIF_DDR_PHY_CTRL_1_BASE_VAL); + + phy >>= OMAP44XX_REG_DDR_PHY_CTRL_1_SHIFT; + + return phy; +} + +/* + * get_lp_mode - Get the LP Mode of a EMIF instance. + * + * It returns the REG_LP_MODE of EMIF_PWR_MGMT_CTRL[10:8] + * for a EMIF. + * + */ +static u32 get_lp_mode(u32 emif_nr) +{ + u32 temp, lpmode; + void __iomem *base = emif[emif_nr].base; + + temp = readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + lpmode = (temp & OMAP44XX_REG_LP_MODE_MASK) >> + OMAP44XX_REG_LP_MODE_SHIFT; + + return lpmode; +} + +/* + * set_lp_mode - Set the LP Mode of a EMIF instance. + * + * It replaces the REG_LP_MODE of EMIF_PWR_MGMT_CTRL[10:8] + * with the new value for a EMIF. + * + */ +static void set_lp_mode(u32 emif_nr, u32 lpmode) +{ + u32 temp; + void __iomem *base = emif[emif_nr].base; + + /* Extract current lp mode value */ + temp = readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + + /* Write out the new lp mode value */ + temp &= ~OMAP44XX_REG_LP_MODE_MASK; + temp |= lpmode << OMAP44XX_REG_LP_MODE_SHIFT; + writel(temp, base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + +} + +/* + * Get the temperature level of the EMIF instance: + * Reads the MR4 register of attached SDRAM parts to find out the temperature + * level. If there are two parts attached(one on each CS), then the temperature + * level for the EMIF instance is the higher of the two temperatures. + */ +static u32 get_temperature_level(u32 emif_nr) +{ + u32 temp, tmp_temperature_level; + bool cs1_used; + void __iomem *base; + + base = emif[emif_nr].base; + + temp = __raw_readl(base + OMAP44XX_EMIF_SDRAM_CONFIG); + cs1_used = (temp & OMAP44XX_REG_EBANK_MASK) ? true : false; + + /* Read mode register 4 */ + __raw_writel(LPDDR2_MR4, base + OMAP44XX_EMIF_LPDDR2_MODE_REG_CFG); + tmp_temperature_level = __raw_readl(base + + OMAP44XX_EMIF_LPDDR2_MODE_REG_DATA); + + tmp_temperature_level = (tmp_temperature_level & + MR4_SDRAM_REF_RATE_MASK) >> + MR4_SDRAM_REF_RATE_SHIFT; + + if (cs1_used) { + __raw_writel(LPDDR2_MR4 | OMAP44XX_REG_CS_MASK, + base + OMAP44XX_EMIF_LPDDR2_MODE_REG_CFG); + temp = __raw_readl(base + OMAP44XX_EMIF_LPDDR2_MODE_REG_DATA); + temp = (temp & MR4_SDRAM_REF_RATE_MASK) + >> MR4_SDRAM_REF_RATE_SHIFT; + tmp_temperature_level = max(temp, tmp_temperature_level); + } + + /* treat everything less than nominal(3) in MR4 as nominal */ + if (unlikely(tmp_temperature_level < SDRAM_TEMP_NOMINAL)) + tmp_temperature_level = SDRAM_TEMP_NOMINAL; + + /* if we get reserved value in MR4 persist with the existing value */ + if (unlikely(tmp_temperature_level == SDRAM_TEMP_RESERVED_4)) + tmp_temperature_level = emif_temperature_level[emif_nr]; + + return tmp_temperature_level; +} + +/* + * Program EMIF shadow registers: + * Sets the shadow registers using pre-caulated register values + * When volt_state indicates that this function is called just before + * a voltage scaling, set only the registers relevant for voltage scaling + * Otherwise, set all the registers relevant for a frequency change + */ +static void setup_registers(u32 emif_nr, struct emif_regs *regs, u32 volt_state) +{ + u32 temp,read_idle; + void __iomem *base = emif[emif_nr].base; + + __raw_writel(regs->ref_ctrl, base + OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW); + + __raw_writel(regs->sdram_tim2, base + OMAP44XX_EMIF_SDRAM_TIM_2_SHDW); + __raw_writel(regs->sdram_tim3, base + OMAP44XX_EMIF_SDRAM_TIM_3_SHDW); + /* + * Do not change the RL part in PHY CTRL register + * RL is not changed during DVFS + */ + temp = __raw_readl(base + OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW); + mask_n_set(temp, OMAP44XX_REG_DDR_PHY_CTRL_1_SHDW_SHIFT, + OMAP44XX_REG_DDR_PHY_CTRL_1_SHDW_MASK, + regs->emif_ddr_phy_ctlr_1_final); + __raw_writel(temp, base + OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW); + + __raw_writel(regs->temp_alert_config, + base + OMAP44XX_EMIF_TEMP_ALERT_CONFIG); + + /* + * When voltage ramps forced read idle should + * happen more often. + */ + if (volt_state == LPDDR2_VOLTAGE_RAMPING) + read_idle = regs->read_idle_ctrl_volt_ramp; + else + read_idle = regs->read_idle_ctrl_normal; + __raw_writel(read_idle, base + OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW); + + /* + * Reading back the last written register to ensure all writes are + * complete + */ + temp = __raw_readl(base + OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW); +} + +/* + * setup_temperature_sensitive_regs() - set the timings for temperature + * sensitive registers. This happens once at initialization time based + * on the temperature at boot time and subsequently based on the temperature + * alert interrupt. Temperature alert can happen when the temperature + * increases or drops. So this function can have the effect of either + * derating the timings or going back to nominal values. + */ +static void setup_temperature_sensitive_regs(u32 emif_nr, + struct emif_regs *regs) +{ + u32 tim1, ref_ctrl, temp_alert_cfg; + void __iomem *base = emif[emif_nr].base; + u32 temperature = emif_temperature_level[emif_nr]; + + if (unlikely(temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH)) { + tim1 = regs->sdram_tim1; + ref_ctrl = regs->ref_ctrl_derated; + temp_alert_cfg = regs->temp_alert_config_derated; + } else if (unlikely(temperature == + SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS)) { + tim1 = regs->sdram_tim1_derated; + ref_ctrl = regs->ref_ctrl_derated; + temp_alert_cfg = regs->temp_alert_config_derated; + } else { + /* + * Nominal timings - you may switch back to the + * nominal timings if the temperature falls + */ + tim1 = regs->sdram_tim1; + ref_ctrl = regs->ref_ctrl; + temp_alert_cfg = regs->temp_alert_config; + } + + __raw_writel(tim1, base + OMAP44XX_EMIF_SDRAM_TIM_1_SHDW); + __raw_writel(temp_alert_cfg, base + OMAP44XX_EMIF_TEMP_ALERT_CONFIG); + __raw_writel(ref_ctrl, base + OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW); + + /* read back last written register to ensure write is complete */ + __raw_readl(base + OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW); +} + +static irqreturn_t handle_temp_alert(void __iomem *base, u32 emif_nr) +{ + u32 old_temperature_level; + old_temperature_level = emif_temperature_level[emif_nr]; + emif_temperature_level[emif_nr] = get_temperature_level(emif_nr); + + if (unlikely(emif_temperature_level[emif_nr] == old_temperature_level)) + return IRQ_HANDLED; + + emif_notify_pending |= (1 << emif_nr); + if (likely(emif_temperature_level[emif_nr] < old_temperature_level)) { + /* Temperature coming down - defer handling to thread */ + emif_thermal_handling_pending |= (1 << emif_nr); + } else if (likely(emif_temperature_level[emif_nr] != + SDRAM_TEMP_VERY_HIGH_SHUTDOWN)) { + /* Temperature is going up - handle immediately */ + setup_temperature_sensitive_regs(emif_nr, + emif_curr_regs[emif_nr]); + /* + * EMIF de-rated timings register needs to be setup using + * freq update method only + */ + omap4_prcm_freq_update(); + } + return IRQ_WAKE_THREAD; +} + +static void setup_volt_sensitive_registers(u32 emif_nr, struct emif_regs *regs, + u32 volt_state) +{ + u32 read_idle; + void __iomem *base = emif[emif_nr].base; + /* + * When voltage ramps forced read idle should + * happen more often. + */ + if (volt_state == LPDDR2_VOLTAGE_RAMPING) + read_idle = regs->read_idle_ctrl_volt_ramp; + else + read_idle = regs->read_idle_ctrl_normal; + + __raw_writel(read_idle, base + OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW); + + /* read back last written register to ensure write is complete */ + __raw_readl(base + OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW); + + return; +} + +/* + * Interrupt Handler for EMIF1 and EMIF2 + */ +static irqreturn_t emif_interrupt_handler(int irq, void *dev_id) +{ + void __iomem *base; + irqreturn_t ret = IRQ_HANDLED; + u32 sys, ll; + u8 emif_nr = EMIF1; + + if (emif[EMIF2].irq == irq) + emif_nr = EMIF2; + + base = emif[emif_nr].base; + + /* Save the status and clear it */ + sys = __raw_readl(base + OMAP44XX_EMIF_IRQSTATUS_SYS); + ll = __raw_readl(base + OMAP44XX_EMIF_IRQSTATUS_LL); + __raw_writel(sys, base + OMAP44XX_EMIF_IRQSTATUS_SYS); + __raw_writel(ll, base + OMAP44XX_EMIF_IRQSTATUS_LL); + /* + * Handle temperature alert + * Temperature alert should be same for both ports + * So, it's enough to process it for only one of the ports + */ + if (sys & OMAP44XX_REG_TA_SYS_MASK) + ret = handle_temp_alert(base, emif_nr); + + if (sys & OMAP44XX_REG_ERR_SYS_MASK) + pr_err("EMIF: Access error from EMIF%d SYS port - %x", + emif_nr, sys); + + if (ll & OMAP44XX_REG_ERR_LL_MASK) + pr_err("EMIF Error: Access error from EMIF%d LL port - %x", + emif_nr, ll); + + return ret; +} + +static irqreturn_t emif_threaded_isr(int irq, void *dev_id) +{ + u8 emif_nr = EMIF1; + if (emif[EMIF2].irq == irq) + emif_nr = EMIF2; + + if (emif_thermal_handling_pending & (1 << emif_nr)) { + setup_temperature_sensitive_regs(emif_nr, + emif_curr_regs[emif_nr]); + /* + * EMIF de-rated timings register needs to be setup using + * freq update method only + */ + omap4_prcm_freq_update(); + /* clear the bit */ + emif_thermal_handling_pending &= ~(1 << emif_nr); + } + if (emif_notify_pending & (1 << emif_nr)) { + sysfs_notify(&(emif[emif_nr].pdev->dev.kobj), NULL, + "temperature"); + kobject_uevent(&(emif[emif_nr].pdev->dev.kobj), KOBJ_CHANGE); + /* clear the bit */ + emif_notify_pending &= ~(1 << emif_nr); + } + + return IRQ_HANDLED; +} + +static int __init setup_emif_interrupts(u32 emif_nr) +{ + u32 temp; + void __iomem *base = emif[emif_nr].base; + int r; + + /* Clear any pendining interrupts */ + __raw_writel(0xFFFFFFFF, base + OMAP44XX_EMIF_IRQSTATUS_SYS); + __raw_writel(0xFFFFFFFF, base + OMAP44XX_EMIF_IRQSTATUS_LL); + + /* Enable the relevant interrupts for both LL and SYS */ + temp = OMAP44XX_REG_EN_TA_SYS_MASK | OMAP44XX_REG_EN_ERR_SYS_MASK; + __raw_writel(temp, base + OMAP44XX_EMIF_IRQENABLE_SET_SYS); + __raw_writel(temp, base + OMAP44XX_EMIF_IRQENABLE_SET_LL); + + /* Dummy read to make sure writes are complete */ + __raw_readl(base + OMAP44XX_EMIF_IRQENABLE_SET_LL); + + /* setup IRQ handlers */ + r = request_threaded_irq(emif[emif_nr].irq, + emif_interrupt_handler, + emif_threaded_isr, + IRQF_SHARED, emif[emif_nr].pdev->name, + emif[emif_nr].pdev); + if (r) { + pr_err("%s: Failed: request_irq emif[%d] IRQ%d:%d\n", + __func__, emif_nr, emif[emif_nr].irq, r); + return r; + } + + /* + * Even if we fail to make the irq wakeup capable, we are at risk only + * while going to suspend where the device is cooler, we might lose a + * bit of power due to pending interrupt preventing core from hitting + * low power state but we can continue to handle events in active use + * cases. So don't free interrupt on failure of marking wakeup capable, + * just warn and continue. + */ + if (enable_irq_wake(emif[emif_nr].irq)) + pr_err("%s: Failed: wakeupen emif[%d] IRQ%d\n", __func__, + emif_nr, emif[emif_nr].irq); + + return 0; +} + +static ssize_t emif_temperature_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 temperature; + if (dev == &(emif[EMIF1].pdev->dev)) + temperature = emif_temperature_level[EMIF1]; + else if (dev == &(emif[EMIF2].pdev->dev)) + temperature = emif_temperature_level[EMIF2]; + else + return 0; + + return snprintf(buf, 20, "%u\n", temperature); +} +static DEVICE_ATTR(temperature, S_IRUGO, emif_temperature_show, NULL); + +static int __devinit omap_emif_probe(struct platform_device *pdev) +{ + int id; + struct resource *res; + + if (!pdev) + return -EINVAL; + + id = pdev->id; + emif[id].pdev = pdev; + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + pr_err("EMIF %i Invalid IRQ resource\n", id); + return -ENODEV; + } + + emif[id].irq = res->start; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + pr_err("EMIF%i Invalid mem resource\n", id); + return -ENODEV; + } + + emif[id].base = ioremap(res->start, SZ_1M); + if (!emif[id].base) { + pr_err("Could not ioremap EMIF%i\n", id); + return -ENOMEM; + } + + pr_info("EMIF%d is enabled with IRQ%d\n", id, emif[id].irq); + + emif[id].ddr_refresh_disabled = false; + + return 0; +} + +static int emif_init(struct omap_hwmod *oh, void *user) +{ + char *name = "omap_emif"; + struct omap_device *od; + static int id; + + od = omap_device_build(name, id, oh, NULL, 0, omap_emif_latency, + ARRAY_SIZE(omap_emif_latency), false); + WARN(IS_ERR(od), "Can't build omap_device for %s:%s.\n", + name, oh->name); + id++; + return 0; + +} + +static void emif_calculate_regs(const struct emif_device_details *devices, + u32 freq, struct emif_regs *regs) +{ + u32 temp; + const struct lpddr2_addressing *addressing; + const struct lpddr2_timings *timings; + const struct lpddr2_min_tck *min_tck; + const struct lpddr2_device_info *cs0_device = devices->cs0_device; + const struct lpddr2_device_info *cs1_device = devices->cs1_device; + + emif_assert(devices); + emif_assert(regs); + /* + * You can not have a device on CS1 without one on CS0 + * So configuring EMIF without a device on CS0 doesn't + * make sense + */ + emif_assert(cs0_device); + emif_assert(cs0_device->type != LPDDR2_TYPE_NVM); + /* + * If there is a device on CS1 it should be same type as CS0 + * (or NVM. But NVM is not supported in this driver yet) + */ + emif_assert((cs1_device == NULL) || + (cs1_device->type == LPDDR2_TYPE_NVM) || + (cs0_device->type == cs1_device->type)); + emif_assert(freq <= MAX_LPDDR2_FREQ); + + set_ddr_clk_period(freq); + + /* + * The device on CS0 is used for all timing calculations + * There is only one set of registers for timings per EMIF. So, if the + * second CS(CS1) has a device, it should have the same timings as the + * device on CS0 + */ + timings = get_timings_table(cs0_device->device_timings, freq); + emif_assert(timings); + min_tck = cs0_device->min_tck; + + temp = + addressing_table_index(cs0_device->type, cs0_device->density, + cs0_device->io_width); + emif_assert((temp >= 0)); + addressing = &(lpddr2_jedec_addressing_table[temp]); + emif_assert(addressing); + + regs->RL_final = timings->RL; + /* + * Initial value of EMIF_SDRAM_CONFIG corresponds to the base + * frequency - 19.2 MHz + */ + regs->sdram_config_init = + get_sdram_config_reg(cs0_device, cs1_device, addressing, + RL_19_2_MHZ); + + regs->sdram_config_final = regs->sdram_config_init; + mask_n_set(regs->sdram_config_final, OMAP44XX_REG_CL_SHIFT, + OMAP44XX_REG_CL_MASK, timings->RL); + + regs->ref_ctrl = get_sdram_ref_ctrl(freq, addressing); + regs->ref_ctrl_derated = regs->ref_ctrl / 4; + + regs->sdram_tim1 = get_sdram_tim_1_reg(timings, min_tck, addressing); + + regs->sdram_tim1_derated = + get_sdram_tim_1_reg_derated(timings, min_tck, addressing); + + regs->sdram_tim2 = get_sdram_tim_2_reg(timings, min_tck); + + regs->sdram_tim3 = get_sdram_tim_3_reg(timings, min_tck, addressing); + + regs->read_idle_ctrl_normal = + get_read_idle_ctrl_reg(LPDDR2_VOLTAGE_STABLE); + + regs->read_idle_ctrl_volt_ramp = + get_read_idle_ctrl_reg(LPDDR2_VOLTAGE_RAMPING); + + regs->zq_config_normal = + get_zq_config_reg(cs1_device, addressing, LPDDR2_VOLTAGE_STABLE); + + regs->zq_config_volt_ramp = + get_zq_config_reg(cs1_device, addressing, LPDDR2_VOLTAGE_RAMPING); + + regs->temp_alert_config = + get_temp_alert_config(cs1_device, addressing, false); + + regs->temp_alert_config_derated = + get_temp_alert_config(cs1_device, addressing, true); + + regs->emif_ddr_phy_ctlr_1_init = + get_ddr_phy_ctrl_1(EMIF_FREQ_19_2_MHZ, RL_19_2_MHZ); + + regs->emif_ddr_phy_ctlr_1_final = + get_ddr_phy_ctrl_1(freq, regs->RL_final); + + /* save the frequency in the struct to act as a tag when cached */ + regs->freq = freq; + + pr_debug("Calculated EMIF configuration register values " + "for %d MHz", freq / 1000000); + pr_debug("sdram_config_init\t\t: 0x%08x\n", regs->sdram_config_init); + pr_debug("sdram_config_final\t\t: 0x%08x\n", regs->sdram_config_final); + pr_debug("sdram_ref_ctrl\t\t: 0x%08x\n", regs->ref_ctrl); + pr_debug("sdram_ref_ctrl_derated\t\t: 0x%08x\n", + regs->ref_ctrl_derated); + pr_debug("sdram_tim_1_reg\t\t: 0x%08x\n", regs->sdram_tim1); + pr_debug("sdram_tim_1_reg_derated\t\t: 0x%08x\n", + regs->sdram_tim1_derated); + pr_debug("sdram_tim_2_reg\t\t: 0x%08x\n", regs->sdram_tim2); + pr_debug("sdram_tim_3_reg\t\t: 0x%08x\n", regs->sdram_tim3); + pr_debug("emif_read_idle_ctrl_normal\t: 0x%08x\n", + regs->read_idle_ctrl_normal); + pr_debug("emif_read_idle_ctrl_dvfs\t: 0x%08x\n", + regs->read_idle_ctrl_volt_ramp); + pr_debug("zq_config_reg_normal\t: 0x%08x\n", regs->zq_config_normal); + pr_debug("zq_config_reg_dvfs\t\t: 0x%08x\n", regs->zq_config_volt_ramp); + pr_debug("temp_alert_config\t: 0x%08x\n", regs->temp_alert_config); + pr_debug("emif_ddr_phy_ctlr_1_init\t: 0x%08x\n", + regs->emif_ddr_phy_ctlr_1_init); + pr_debug("emif_ddr_phy_ctlr_1_final\t: 0x%08x\n", + regs->emif_ddr_phy_ctlr_1_final); +} + +/* + * get_regs() - gets the cached emif_regs structure for a given EMIF instance + * (emif_nr) for a given frequency(freq): + * + * As an optimization, only one cache array(that of EMIF1) if both EMIF1 and + * EMIF2 has identical devices + * + * If we do not have an entry corresponding to the frequency given, we + * allocate a new entry and calculate the values + */ +static struct emif_regs *get_regs(u32 emif_nr, u32 freq) +{ + int i; + struct emif_regs **regs_cache; + struct emif_regs *regs = NULL; + + /* + * If EMIF2 has the same devices as EMIF1 use the register + * cache of EMIF1 + */ + if ((emif_nr == EMIF1) || + ((emif_nr == EMIF2) + && (emif_devices[EMIF1] == emif_devices[EMIF2]))) + regs_cache = emif1_regs_cache; + else + regs_cache = emif2_regs_cache; + + for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) { + if (regs_cache[i]->freq == freq) { + regs = regs_cache[i]; + break; + } + } + + /* + * If we don't have an entry for this frequency in the cache create one + * and calculate the values + */ + if (!regs) { + regs = kmalloc(sizeof(struct emif_regs), GFP_ATOMIC); + if (!regs) + return NULL; + emif_calculate_regs(emif_devices[emif_nr], freq, regs); + + /* + * Now look for an un-used entry in the cache and save the + * newly created struct. If there are no free entries + * over-write the last entry + */ + for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) + ; + + if (i >= EMIF_MAX_NUM_FREQUENCIES) { + pr_warning("emif: emif regs_cache full - more number" + " of frequencies used than expected!!"); + i = EMIF_MAX_NUM_FREQUENCIES - 1; + kfree(regs_cache[i]); + } + regs_cache[i] = regs; + } + return regs; +} + +static int do_emif_setup_registers(u32 emif_nr, u32 freq, u32 volt_state) +{ + struct emif_regs *regs; + regs = get_regs(emif_nr, freq); + if (!regs) + return -ENOMEM; + + emif_curr_regs[emif_nr] = regs; + setup_registers(emif_nr, regs, volt_state); + setup_temperature_sensitive_regs(emif_nr, regs); + + return 0; +} + +static int do_setup_device_details(u32 emif_nr, + const struct emif_device_details *devices) +{ + if (!emif_devices[emif_nr]) { + emif_devices[emif_nr] = + kmalloc(sizeof(struct emif_device_details), GFP_KERNEL); + if (!emif_devices[emif_nr]) + return -ENOMEM; + *emif_devices[emif_nr] = *devices; + } + + return 0; +} + +/* + * Initialize the temperature level and setup the sysfs nodes + * and uvent for temperature monitoring + */ +static void init_temperature(u32 emif_nr) +{ + if (!emif_devices[emif_nr]) + return; + + emif_temperature_level[emif_nr] = get_temperature_level(emif_nr); + WARN_ON(device_create_file(&(emif[emif_nr].pdev->dev), + &dev_attr_temperature)); + kobject_uevent(&(emif[emif_nr].pdev->dev.kobj), KOBJ_ADD); + + if (emif_temperature_level[emif_nr] == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) + pr_emerg("EMIF %d: SDRAM temperature exceeds operating" + "limit.. Needs shut down!!!", emif_nr + 1); +} + +/* + * omap_emif_device_init needs to be done before + * ddr reconfigure function call. + * Hence omap_emif_device_init is a postcore_initcall. + */ +static int __init omap_emif_device_init(void) +{ + /* + * To avoid code running on other OMAPs in + * multi-omap builds + */ + if (!cpu_is_omap44xx()) + return -ENODEV; + + return omap_hwmod_for_each_by_class("emif", emif_init, NULL); +} +postcore_initcall(omap_emif_device_init); + + +/* We need to disable interrupts of the EMIF + * module, because in a warm reboot scenario, there + * may be a pending irq that is not serviced and emif + * is stuck in transition. On the next boot HW mod + * fails emif inizalization with a timeout. + */ +void emif_clear_irq(int emif_id) +{ + u32 irq_mask = 0; + u32 base = 0; + u32 reg = 0; + + if (emif_id == 0) + base = OMAP44XX_EMIF1_VIRT; + else + base = OMAP44XX_EMIF2_VIRT; + + /* Disable the relevant interrupts for both LL and SYS */ + irq_mask = OMAP44XX_REG_EN_TA_SYS_MASK | OMAP44XX_REG_EN_ERR_SYS_MASK + | OMAP44XX_REG_EN_DNV_SYS_MASK; + __raw_writel(irq_mask, base + OMAP44XX_EMIF_IRQENABLE_CLR_SYS); + __raw_writel(irq_mask, base + OMAP44XX_EMIF_IRQENABLE_CLR_LL); + + /* Clear any pendining interrupts without overwritng reserved bits*/ + reg = __raw_readl(base + OMAP44XX_EMIF_IRQSTATUS_SYS); + reg |= irq_mask; + __raw_writel(reg, base + OMAP44XX_EMIF_IRQSTATUS_SYS); + + reg = __raw_readl(base + OMAP44XX_EMIF_IRQSTATUS_LL); + reg |= irq_mask; + __raw_writel(reg, base + OMAP44XX_EMIF_IRQSTATUS_LL); + + /* Dummy read to make sure writes are complete */ + __raw_readl(base + OMAP44XX_EMIF_IRQENABLE_SET_LL); + + return; +} + +void emif_driver_shutdown(struct platform_device *pdev) +{ + emif_clear_irq(pdev->id); +} + +static struct platform_driver omap_emif_driver = { + .probe = omap_emif_probe, + .driver = { + .name = "omap_emif", + }, + + .shutdown = emif_driver_shutdown, +}; + +static int __init omap_emif_register(void) +{ + return platform_driver_register(&omap_emif_driver); +} +postcore_initcall(omap_emif_register); + +/* + * omap_emif_notify_voltage - setup the voltage sensitive + * registers based on the voltage situation (voltage ramping or stable) + * read_idle_ctrl and zq_config are the registers that are voltage sensitive + * They need to have a very safe value(more frequent zq calibration and + * read idle forcing) when voltage is scaling and can have a more relaxed + * nominal value(frequency dependent) when voltage is stable + */ +int omap_emif_notify_voltage(struct notifier_block *nb, + unsigned long val, void *data) +{ + u32 volt_state; + + if (val == OMAP_VOLTAGE_PRECHANGE) + volt_state = LPDDR2_VOLTAGE_RAMPING; + else + volt_state = LPDDR2_VOLTAGE_STABLE; + + if (likely(emif_curr_regs[EMIF1])) + setup_volt_sensitive_registers(EMIF1, emif_curr_regs[EMIF1], + volt_state); + + if (likely(emif_curr_regs[EMIF2])) + setup_volt_sensitive_registers(EMIF2, emif_curr_regs[EMIF2], + volt_state); + + if (unlikely(!emif_curr_regs[EMIF1] && !emif_curr_regs[EMIF2])) { + pr_err_once("emif: voltage state notification came before the" + " initial setup - ignoring the notification"); + return -EINVAL; + } + + /* + * EMIF read-idle control needs to be setup using + * freq update method only + */ + return omap4_prcm_freq_update(); +} + +static struct notifier_block emif_volt_notifier_block = { + .notifier_call = omap_emif_notify_voltage, +}; + +static int __init omap_emif_late_init(void) +{ + struct voltagedomain *voltdm = voltdm_lookup("core"); + + if (!voltdm) { + pr_err("CORE voltage domain lookup failed\n"); + return -EINVAL; + } + + voltdm_register_notifier(voltdm, &emif_volt_notifier_block); + + return 0; +} +late_initcall(omap_emif_late_init); + +/* + * omap_emif_setup_registers - setup the shadow registers for a given + * frequency. This will be typically followed by a FREQ_UPDATE procedure + * to lock at the new frequency and this will update the EMIF main registers + * with shadow register values + */ +int omap_emif_setup_registers(u32 freq, u32 volt_state) +{ + int err = 0; + if (likely(emif_devices[EMIF1])) + err = do_emif_setup_registers(EMIF1, freq, volt_state); + if (likely(!err && emif_devices[EMIF2])) + err = do_emif_setup_registers(EMIF2, freq, volt_state); + return err; +} + + +/* + * omap_emif_frequency_pre_notify - Disable DDR self refresh of both EMIFs + * + * It disables the LP mode if the LP mode of EMIFs was LP_MODE_SELF_REFRESH. + * + * It should be called before any PRCM frequency update sequence. + * After the frequency update sequence, omap_emif_frequency_post_notify + * should be called to restore the original LP MODE setting of the EMIFs. + * + */ +void omap_emif_frequency_pre_notify(void) +{ + int emif_num; + + for (emif_num = EMIF1; emif_num < EMIF_NUM_INSTANCES; emif_num++) { + + /* + * Only disable ddr self-refresh + * if ddr self-refresh was enabled + */ + if (likely(LP_MODE_SELF_REFRESH == get_lp_mode(emif_num))) { + + set_lp_mode(emif_num, LP_MODE_DISABLE); + emif[emif_num].ddr_refresh_disabled = true; + } + + } +} + +/* + * omap_emif_frequency_post_notify - Enable DDR self refresh of both EMIFs + * + * It restores the LP mode of the EMIFs back to LP_MODE_SELF_REFRESH if it + * was previously disabled by omap_emif_frequency_pre_notify() + * + */ +void omap_emif_frequency_post_notify(void) +{ + int emif_num; + + for (emif_num = EMIF1; emif_num < EMIF_NUM_INSTANCES; emif_num++) { + + /* + * Only re-enable ddr self-refresh + * if ddr self-refresh was disabled + */ + if (likely(emif[emif_num].ddr_refresh_disabled)) { + + set_lp_mode(emif_num, LP_MODE_SELF_REFRESH); + emif[emif_num].ddr_refresh_disabled = false; + } + } +} + +/* + * omap_emif_setup_device_details - save the SDRAM device details passed + * from the board file + */ +int omap_emif_setup_device_details(const struct emif_device_details + *emif1_devices, + const struct emif_device_details + *emif2_devices) +{ + if (emif1_devices) + BUG_ON(do_setup_device_details(EMIF1, emif1_devices)); + + /* + * If memory devices connected to both the EMIFs are identical + * (which is normally the case), then no need to calculate the + * registers again for EMIF1 and allocate the structure for registers + */ + if (emif2_devices && (emif1_devices != emif2_devices)) + BUG_ON(do_setup_device_details(EMIF2, emif2_devices)); + else if (emif2_devices) { + emif_devices[EMIF2] = emif_devices[EMIF1]; + /* call for temperature related setup */ + BUG_ON(do_setup_device_details(EMIF2, emif2_devices)); + } + + return 0; +} + +static void __init setup_lowpower_regs(u32 emif_nr, + struct emif_device_details *emif_dev) +{ + u32 temp; + void __iomem *base = emif[emif_nr].base; + const struct lpddr2_device_info *dev; + + if (!emif_dev) { + pr_err("%s: no emif %d\n", __func__, emif_nr); + return; + } + + /* + * All devices on this specific EMIF should have the same Selfrefresh + * timing, so use cs0 + */ + dev = emif_dev->cs0_device; + if (!dev) { + pr_err("%s: no CS0 device in emif %d\n", __func__, emif_nr); + return; + } + if (dev->emif_ddr_selfrefresh_cycles >= 0) { + u32 num_cycles, ddr_sr_timer; + + /* Enable self refresh if not already configured */ + temp = __raw_readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL) & + OMAP44XX_REG_LP_MODE_MASK; + /* + * Configure the self refresh timing + * base value starts at 16 cycles mapped to 1( __fls(16) = 4) + */ + num_cycles = dev->emif_ddr_selfrefresh_cycles; + if (num_cycles >= 16) + ddr_sr_timer = __fls(num_cycles) - 3; + else + ddr_sr_timer = 0; + + /* Program the idle delay */ + temp = __raw_readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW); + mask_n_set(temp, OMAP44XX_REG_SR_TIM_SHDW_SHIFT, + OMAP44XX_REG_SR_TIM_SHDW_MASK, ddr_sr_timer); + /* + * Some weird magic number to a field which should'nt impact.. + * but seems to make this work.. + */ + mask_n_set(temp, OMAP44XX_REG_CS_TIM_SHDW_SHIFT, + OMAP44XX_REG_CS_TIM_SHDW_MASK, 0xf); + __raw_writel(temp, base + OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW); + + /* Enable Self Refresh */ + temp = __raw_readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + mask_n_set(temp, OMAP44XX_REG_LP_MODE_SHIFT, + OMAP44XX_REG_LP_MODE_MASK, LP_MODE_SELF_REFRESH); + __raw_writel(temp, base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + } else { + /* Disable Automatic power management if < 0 and not disabled */ + temp = __raw_readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL) & + OMAP44XX_REG_LP_MODE_MASK; + + temp = __raw_readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW); + mask_n_set(temp, OMAP44XX_REG_SR_TIM_SHDW_SHIFT, + OMAP44XX_REG_SR_TIM_SHDW_MASK, 0x0); + __raw_writel(temp, base + OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW); + + temp = __raw_readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + mask_n_set(temp, OMAP44XX_REG_LP_MODE_SHIFT, + OMAP44XX_REG_LP_MODE_MASK, LP_MODE_DISABLE); + __raw_writel(temp, base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + } +} + +/* + * omap_init_emif_timings - reprogram EMIF timing parameters + * + * Sets the CORE DPLL3 M2 divider to the same value that it's at + * currently. This has the effect of setting the EMIF DDR AC timing + * registers to the values currently defined by the kernel. + */ +static int __init omap_init_emif_timings(void) +{ + struct clk *dpll_core_m2_clk; + int ret; + long rate; + + /* + * Setup the initial temperatures sysfs nodes etc. + * Subsequent updates to temperature is done through interrupts + */ + init_temperature(EMIF1); + init_temperature(EMIF2); + + /* FREQ_UPDATE sequence isn't supported on early vesion */ + if (omap_rev() == OMAP4430_REV_ES1_0) + return -EINVAL; + + dpll_core_m2_clk = clk_get(NULL, "dpll_core_m2_ck"); + if (!dpll_core_m2_clk) + pr_err("Could not get LPDDR2 clock - dpll_core_m2_ck\n"); + + rate = clk_get_rate(dpll_core_m2_clk); + pr_info("Reprogramming LPDDR2 timings to %ld Hz\n", rate >> 1); + + ret = clk_set_rate(dpll_core_m2_clk, rate); + if (ret) + pr_err("Unable to set LPDDR2 rate to %ld:\n", rate); + + /* registers are setup correctly - now enable interrupts */ + if (emif_devices[EMIF1]) { + ret = setup_emif_interrupts(EMIF1); + setup_lowpower_regs(EMIF1, emif_devices[EMIF1]); + } + if (!ret && emif_devices[EMIF2]) { + ret = setup_emif_interrupts(EMIF2); + setup_lowpower_regs(EMIF2, emif_devices[EMIF2]); + } + + clk_put(dpll_core_m2_clk); + + return ret; +} +late_initcall(omap_init_emif_timings); diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c index 9529842..1045c72 100644 --- a/arch/arm/mach-omap2/gpio.c +++ b/arch/arm/mach-omap2/gpio.c @@ -23,6 +23,9 @@ #include <plat/omap_hwmod.h> #include <plat/omap_device.h> +#include <plat/omap-pm.h> + +#include "powerdomain.h" static struct omap_device_pm_latency omap_gpio_latency[] = { [0] = { @@ -39,6 +42,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) struct omap_gpio_dev_attr *dev_attr; char *name = "omap_gpio"; int id; + struct powerdomain *pwrdm; /* * extract the device id from name field available in the @@ -58,16 +62,77 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) dev_attr = (struct omap_gpio_dev_attr *)oh->dev_attr; pdata->bank_width = dev_attr->bank_width; + pdata->suspend_support = true; pdata->dbck_flag = dev_attr->dbck_flag; pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1); + pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL); + if (!pdata) { + pr_err("gpio%d: Memory allocation failed\n", id); + return -ENOMEM; + } + + pdata->regs->irqctrl = USHRT_MAX; + pdata->regs->edgectrl1 = USHRT_MAX; + pdata->regs->edgectrl2 = USHRT_MAX; + switch (oh->class->rev) { case 0: + if (id == 1) + /* non-wakeup GPIO pins for OMAP2 Bank1 */ + pdata->non_wakeup_gpios = 0xe203ffc0; + else if (id == 2) + /* non-wakeup GPIO pins for OMAP2 Bank2 */ + pdata->non_wakeup_gpios = 0x08700040; + /* fall through */ + case 1: - pdata->bank_type = METHOD_GPIO_24XX; + pdata->regs->revision = OMAP24XX_GPIO_REVISION; + pdata->regs->direction = OMAP24XX_GPIO_OE; + pdata->regs->datain = OMAP24XX_GPIO_DATAIN; + pdata->regs->dataout = OMAP24XX_GPIO_DATAOUT; + pdata->regs->set_dataout = OMAP24XX_GPIO_SETDATAOUT; + pdata->regs->clr_dataout = OMAP24XX_GPIO_CLEARDATAOUT; + pdata->regs->irqstatus = OMAP24XX_GPIO_IRQSTATUS1; + pdata->regs->irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2; + pdata->regs->irqenable = OMAP24XX_GPIO_IRQENABLE1; + pdata->regs->irqenable2 = OMAP24XX_GPIO_IRQENABLE2; + pdata->regs->set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1; + pdata->regs->clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1; + pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL; + pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN; + pdata->regs->ctrl = OMAP24XX_GPIO_CTRL; + pdata->regs->wkup_status = OMAP24XX_GPIO_WAKE_EN; + pdata->regs->wkup_clear = OMAP24XX_GPIO_CLEARWKUENA; + pdata->regs->wkup_set = OMAP24XX_GPIO_SETWKUENA; + pdata->regs->leveldetect0 = OMAP24XX_GPIO_LEVELDETECT0; + pdata->regs->leveldetect1 = OMAP24XX_GPIO_LEVELDETECT1; + pdata->regs->risingdetect = OMAP24XX_GPIO_RISINGDETECT; + pdata->regs->fallingdetect = OMAP24XX_GPIO_FALLINGDETECT; break; case 2: - pdata->bank_type = METHOD_GPIO_44XX; + pdata->regs->revision = OMAP4_GPIO_REVISION; + pdata->regs->direction = OMAP4_GPIO_OE; + pdata->regs->datain = OMAP4_GPIO_DATAIN; + pdata->regs->dataout = OMAP4_GPIO_DATAOUT; + pdata->regs->set_dataout = OMAP4_GPIO_SETDATAOUT; + pdata->regs->clr_dataout = OMAP4_GPIO_CLEARDATAOUT; + pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0; + pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1; + pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0; + pdata->regs->irqenable2 = OMAP4_GPIO_IRQSTATUSSET1; + pdata->regs->set_irqenable = OMAP4_GPIO_IRQSTATUSSET0; + pdata->regs->clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0; + pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME; + pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE; + pdata->regs->ctrl = OMAP4_GPIO_CTRL; + pdata->regs->wkup_status = OMAP4_GPIO_IRQWAKEN0; + pdata->regs->wkup_clear = OMAP4_GPIO_IRQWAKEN0; + pdata->regs->wkup_set = OMAP4_GPIO_IRQWAKEN0; + pdata->regs->leveldetect0 = OMAP4_GPIO_LEVELDETECT0; + pdata->regs->leveldetect1 = OMAP4_GPIO_LEVELDETECT1; + pdata->regs->risingdetect = OMAP4_GPIO_RISINGDETECT; + pdata->regs->fallingdetect = OMAP4_GPIO_FALLINGDETECT; break; default: WARN(1, "Invalid gpio bank_type\n"); @@ -75,6 +140,9 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) return -EINVAL; } + pwrdm = omap_hwmod_get_pwrdm(oh); + pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm); + od = omap_device_build(name, id - 1, oh, pdata, sizeof(*pdata), omap_gpio_latency, ARRAY_SIZE(omap_gpio_latency), @@ -87,7 +155,6 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) return PTR_ERR(od); } - gpio_bank_count++; return 0; } diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index dfffbbf..5610d10 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -78,9 +78,9 @@ struct gpmc_cs_config { /* * Structure to save/restore gpmc context - * to support core off on OMAP3 + * to support core off. */ -struct omap3_gpmc_regs { +struct omap_gpmc_regs { u32 sysconfig; u32 irqenable; u32 timeout_ctrl; @@ -776,10 +776,9 @@ static irqreturn_t gpmc_handle_irq(int irq, void *dev) return IRQ_HANDLED; } -#ifdef CONFIG_ARCH_OMAP3 -static struct omap3_gpmc_regs gpmc_context; +static struct omap_gpmc_regs gpmc_context; -void omap3_gpmc_save_context(void) +void omap_gpmc_save_context(void) { int i; @@ -811,7 +810,7 @@ void omap3_gpmc_save_context(void) } } -void omap3_gpmc_restore_context(void) +void omap_gpmc_restore_context(void) { int i; @@ -841,7 +840,6 @@ void omap3_gpmc_restore_context(void) } } } -#endif /* CONFIG_ARCH_OMAP3 */ /** * gpmc_enable_hwecc - enable hardware ecc functionality diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 66868c5..0201705 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -31,16 +31,6 @@ static u16 control_mmc1; #define HSMMC_NAME_LEN 9 -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) - -static int hsmmc_get_context_loss(struct device *dev) -{ - return omap_pm_get_dev_context_loss_count(dev); -} - -#else -#define hsmmc_get_context_loss NULL -#endif static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, int power_on, int vdd) @@ -318,8 +308,6 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, else mmc->reg_offset = 0; - mmc->get_context_loss_count = hsmmc_get_context_loss; - mmc->slots[0].switch_pin = c->gpio_cd; mmc->slots[0].gpio_wp = c->gpio_wp; @@ -344,6 +332,20 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, if (c->vcc_aux_disable_is_sleep) mmc->slots[0].vcc_aux_disable_is_sleep = 1; + if (cpu_is_omap44xx()) { + if (omap_rev() > OMAP4430_REV_ES1_0) + mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET; + if (c->mmc >= 3 && c->mmc <= 5) + mmc->slots[0].features |= HSMMC_HAS_48MHZ_MASTER_CLK; + } + + if (c->mmc_data) { + memcpy(&mmc->slots[0].mmc_data, c->mmc_data, + sizeof(struct mmc_platform_data)); + mmc->slots[0].card_detect = + (mmc_card_detect_func)c->mmc_data->status; + } + /* * NOTE: MMC slots should have a Vcc regulator set up. * This may be from a TWL4030-family chip, another diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index f757e78..2cbe0f9 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -6,8 +6,12 @@ * published by the Free Software Foundation. */ +#include <asm/mach/mmc.h> + struct mmc_card; +typedef int (*mmc_card_detect_func)(struct device *dev, int slot); + struct omap2_hsmmc_info { u8 mmc; /* controller 1/2/3 */ u32 caps; /* 4/8 wires and any additional host @@ -25,6 +29,7 @@ struct omap2_hsmmc_info { char *name; /* or NULL for default */ struct device *dev; /* returned: pointer to mmc adapter */ int ocr_mask; /* temporary HACK */ + struct mmc_platform_data *mmc_data; /* Remux (pad configuration) when powering on/off */ void (*remux)(struct device *dev, int slot, int power_on); /* init some special card */ diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 2537090..a90630d 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -32,6 +32,7 @@ static struct omap_chip_id omap_chip; static unsigned int omap_revision; u32 omap3_features; +u32 omap4_features; unsigned int omap_rev(void) { @@ -88,6 +89,8 @@ EXPORT_SYMBOL(omap_type); #define OMAP_TAP_DIE_ID_44XX_1 0x0208 #define OMAP_TAP_DIE_ID_44XX_2 0x020c #define OMAP_TAP_DIE_ID_44XX_3 0x0210 +#define OMAP_TAP_PROD_ID_44XX_0 0x0214 +#define OMAP_TAP_PROD_ID_44XX_1 0x0218 #define read_tap_reg(reg) __raw_readl(tap_base + (reg)) @@ -126,6 +129,16 @@ void omap_get_die_id(struct omap_die_id *odi) odi->id_3 = read_tap_reg(OMAP_TAP_DIE_ID_3); } +void omap_get_production_id(struct omap_die_id *odi) +{ + if (cpu_is_omap44xx()) { + odi->id_0 = read_tap_reg(OMAP_TAP_PROD_ID_44XX_0); + odi->id_1 = read_tap_reg(OMAP_TAP_PROD_ID_44XX_1); + odi->id_2 = 0; + odi->id_3 = 0; + } +} + static void __init omap24xx_check_revision(void) { int i, j; @@ -212,6 +225,34 @@ static void __init omap3_check_features(void) */ } +static void __init omap4_check_features(void) +{ + u32 si_type; + + omap4_features = 0; + + if (cpu_is_omap443x()) + omap4_features |= OMAP4_HAS_MPU_1GHZ; + + + if (cpu_is_omap446x()) { + si_type = + read_tap_reg(OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_1); + switch ((si_type & (3 << 16)) >> 16) { + case 2: + /* High performance device */ + omap4_features |= OMAP4_HAS_MPU_1_5GHZ; + omap4_features |= OMAP4_HAS_MPU_1_2GHZ; + break; + case 1: + default: + /* Standard device */ + omap4_features |= OMAP4_HAS_MPU_1_2GHZ; + break; + } + } +} + static void __init ti816x_check_features(void) { omap3_features = OMAP3_HAS_NEON; @@ -331,8 +372,13 @@ static void __init omap3_check_revision(void) static void __init omap4_check_revision(void) { u32 idcode; - u16 hawkeye; u8 rev; + /* + * NOTE: OMAP4460+ uses ramp system for identification and hawkeye + * variable is reused for the same. Since the values are unique + * we continue to use the current system + */ + u16 hawkeye; /* * The IC rev detection is done with hawkeye and rev. @@ -344,10 +390,10 @@ static void __init omap4_check_revision(void) rev = (idcode >> 28) & 0xf; /* - * Few initial ES2.0 samples IDCODE is same as ES1.0 + * Few initial 4430 ES2.0 samples IDCODE is same as ES1.0 * Use ARM register to detect the correct ES version */ - if (!rev) { + if (!rev && (hawkeye != 0xb94e)) { idcode = read_cpuid(CPUID_ID); rev = (idcode & 0xf) - 1; } @@ -377,6 +423,19 @@ static void __init omap4_check_revision(void) omap_chip.oc |= CHIP_IS_OMAP4430ES2_2; } break; + case 0xb94e: + switch (rev) { + case 0: + omap_revision = OMAP4460_REV_ES1_0; + omap_chip.oc |= CHIP_IS_OMAP4460ES1_0; + break; + case 2: + default: + omap_revision = OMAP4460_REV_ES1_1; + omap_chip.oc |= CHIP_IS_OMAP4460ES1_1; + break; + } + break; default: /* Unknown default to latest silicon rev as default */ omap_revision = OMAP4430_REV_ES2_2; @@ -518,6 +577,7 @@ void __init omap2_check_revision(void) return; } else if (cpu_is_omap44xx()) { omap4_check_revision(); + omap4_check_features(); return; } else { pr_err("OMAP revision unknown, please fix!\n"); diff --git a/arch/arm/mach-omap2/include/mach/barriers.h b/arch/arm/mach-omap2/include/mach/barriers.h new file mode 100644 index 0000000..aa72a33 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/barriers.h @@ -0,0 +1,48 @@ +/* + * OMAP memory barrier header. + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * Richard Woodruff <r-woodruff2@ti.com> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __MACH_BARRIERS_H +#define __MACH_BARRIERS_H + +#include <linux/types.h> + +/* provide func ptr so to allow safe calling at any point */ +struct omap_bus_post_fns { + void (*sync)(void); +}; + +extern struct omap_bus_post_fns omap_bus_post; + +#ifdef CONFIG_ARCH_OMAP4 +static inline void bus_sync(void) +{ + omap_bus_post.sync(); +} +#else +static inline void bus_sync(void) +{ } +#endif + +#define rmb() dsb() +#define wmb() do { dsb(); outer_sync(); bus_sync(); } while (0) +#define mb() wmb() + +#endif /* __MACH_BARRIERS_H */ diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h index 2f7ac70..58983a1 100644 --- a/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h +++ b/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h @@ -163,6 +163,7 @@ /* STD_FUSE_OPP_BGAP */ #define OMAP4_STD_FUSE_OPP_BGAP_SHIFT 0 #define OMAP4_STD_FUSE_OPP_BGAP_MASK (0xffffffff << 0) +#define OMAP4_STD_FUSE_OPP_BGAP_MASK_LSB (0xffff << 16) /* STD_FUSE_OPP_DPLL_0 */ #define OMAP4_STD_FUSE_OPP_DPLL_0_SHIFT 0 @@ -257,18 +258,50 @@ #define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_MASK (0x1f << 0) /* TEMP_SENSOR */ -#define OMAP4_BGAP_TEMPSOFF_SHIFT 12 -#define OMAP4_BGAP_TEMPSOFF_MASK (1 << 12) -#define OMAP4_BGAP_TSHUT_SHIFT 11 -#define OMAP4_BGAP_TSHUT_MASK (1 << 11) -#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 10 -#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 10) -#define OMAP4_BGAP_TEMP_SENSOR_SOC_SHIFT 9 -#define OMAP4_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9) -#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8 -#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8) -#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0 -#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0) +#define OMAP4_BGAP_TEMPSOFF_SHIFT 13 +#define OMAP4_BGAP_TEMPSOFF_MASK (1 << 13) +#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_SHIFT 12 +#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_MASK (1 << 12) +#define OMAP4_BGAP_TEMP_SENSOR_SOC_SHIFT 11 +#define OMAP4_BGAP_TEMP_SENSOR_SOC_MASK (1 << 11) +#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_SHIFT 10 +#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 10) +#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0 +#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0) + +/* BANDGAP_CTRL */ +#define OMAP4_SINGLE_MODE_SHIFT 31 +#define OMAP4_SINGLE_MODE_MASK (1 << 31) +#define OMAP4_MASK_HOT_SHIFT 1 +#define OMAP4_MASK_HOT_MASK (1 << 1) +#define OMAP4_MASK_COLD_SHIFT 0 +#define OMAP4_MASK_COLD_MASK (1 << 0) + +/* BANDGAP_COUNTER */ +#define OMAP4_COUNTER_SHIFT 0 +#define OMAP4_COUNTER_MASK (0xffffff << 0) + +/* BANDGAP_THRESHOLD */ +#define OMAP4_T_HOT_SHIFT 16 +#define OMAP4_T_HOT_MASK (0x3ff << 16) +#define OMAP4_T_COLD_SHIFT 0 +#define OMAP4_T_COLD_MASK (0x3ff << 0) + +/* TSHUT_THRESHOLD */ +#define OMAP4_TSHUT_HOT_SHIFT 16 +#define OMAP4_TSHUT_HOT_MASK (0x3ff << 16) +#define OMAP4_TSHUT_COLD_SHIFT 0 +#define OMAP4_TSHUT_COLD_MASK (0x3ff << 0) + +/* BANDGAP_STATUS */ +#define OMAP4_CLEAN_STOP_SHIFT 3 +#define OMAP4_CLEAN_STOP_MASK (1 << 3) +#define OMAP4_BGAP_ALERT_SHIFT 2 +#define OMAP4_BGAP_ALERT_MASK (1 << 2) +#define OMAP4_HOT_FLAG_SHIFT 1 +#define OMAP4_HOT_FLAG_MASK (1 << 1) +#define OMAP4_COLD_FLAG_SHIFT 0 +#define OMAP4_COLD_FLAG_MASK (1 << 0) /* DPLL_NWELL_TRIM_0 */ #define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_SHIFT 29 diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h index c88420d..852a3a9 100644 --- a/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h +++ b/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h @@ -1185,6 +1185,14 @@ #define OMAP4_LPDDR21_VREF_DQ_TAP0_MASK (1 << 13) #define OMAP4_LPDDR21_VREF_DQ_TAP1_SHIFT 12 #define OMAP4_LPDDR21_VREF_DQ_TAP1_MASK (1 << 12) +#define OMAP4_LPDDR21_VREF_EN_CA_SHIFT 3 +#define OMAP4_LPDDR21_VREF_EN_CA_MASK (1 << 3) +#define OMAP4_LPDDR21_VREF_EN_DQ_SHIFT 2 +#define OMAP4_LPDDR21_VREF_EN_DQ_MASK (1 << 2) +#define OMAP4_LPDDR21_VREF_AUTO_EN_CA_SHIFT 1 +#define OMAP4_LPDDR21_VREF_AUTO_EN_CA_MASK (1 << 1) +#define OMAP4_LPDDR21_VREF_AUTO_EN_DQ_SHIFT 0 +#define OMAP4_LPDDR21_VREF_AUTO_EN_DQ_MASK (1 << 0) /* CONTROL_LPDDR2IO2_0 */ #define OMAP4_LPDDR2IO2_GR4_SR_SHIFT 30 diff --git a/arch/arm/mach-omap2/include/mach/dmm-44xx.h b/arch/arm/mach-omap2/include/mach/dmm-44xx.h new file mode 100644 index 0000000..c25dda5 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/dmm-44xx.h @@ -0,0 +1,363 @@ +/* + * OMAP44xx DMM_CORE registers and bitfields + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * Benoit Cousson (b-cousson@ti.com) + * Santosh Shilimkar (santosh.shilimkar@ti.com) + * + * This file is automatically generated from the OMAP hardware databases. + * We respectfully ask that any modifications to this file be coordinated + * with the public linux-omap@vger.kernel.org mailing list and the + * authors above to ensure that the autogeneration scripts are kept + * up-to-date with the file contents. + * + * 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. + */ + +#ifndef __ARCH_ARM_MACH_OMAP2_DMM_CORE_44XX_H +#define __ARCH_ARM_MACH_OMAP2_DMM_CORE_44XX_H + + +/* Base address */ +#define OMAP44XX_DMM__DMM 0x4e000000 + +/* Registers offset */ +#define OMAP44XX_DMM_REVISION 0x0000 +#define OMAP44XX_DMM_HWINFO 0x0004 +#define OMAP44XX_DMM_LISA_HWINFO 0x0008 +#define OMAP44XX_DMM_SYSCONFIG 0x0010 +#define OMAP44XX_DMM_LISA_LOCK 0x001c +#define OMAP44XX_DMM_LISA_MAP 0x0040 +#define OMAP44XX_DMM_TILER_HWINFO 0x0208 +#define OMAP44XX_DMM_TILER_OR 0x0220 +#define OMAP44XX_DMM_PAT_HWINFO 0x0408 +#define OMAP44XX_DMM_PAT_GEOMETRY 0x040c +#define OMAP44XX_DMM_PAT_CONFIG 0x0410 +#define OMAP44XX_DMM_PAT_VIEW 0x0420 +#define OMAP44XX_DMM_PAT_VIEW_MAP 0x0440 +#define OMAP44XX_DMM_PAT_VIEW_MAP_BASE 0x0460 +#define OMAP44XX_DMM_PAT_IRQ_EOI 0x0478 +#define OMAP44XX_DMM_PAT_IRQSTATUS_RAW 0x0480 +#define OMAP44XX_DMM_PAT_IRQSTATUS 0x0490 +#define OMAP44XX_DMM_PAT_IRQENABLE_SET 0x04a0 +#define OMAP44XX_DMM_PAT_IRQENABLE_CLR 0x04b0 +#define OMAP44XX_DMM_PAT_STATUS 0x04c0 +#define OMAP44XX_DMM_PAT_DESCR 0x0500 +#define OMAP44XX_DMM_PAT_AREA 0x0504 +#define OMAP44XX_DMM_PAT_CTRL 0x0508 +#define OMAP44XX_DMM_PAT_DATA 0x050c +#define OMAP44XX_DMM_PEG_HWINFO 0x0608 +#define OMAP44XX_DMM_PEG_PRIO 0x0620 +#define OMAP44XX_DMM_PEG_PRIO_PAT 0x0640 + +/* Registers shifts and masks */ + +/* DMM_REVISION */ +#define OMAP44XX_SCHEME_SHIFT 30 +#define OMAP44XX_SCHEME_MASK (0x3 << 30) +#define OMAP44XX_FUNC_SHIFT 16 +#define OMAP44XX_FUNC_MASK (0xfff << 16) +#define OMAP44XX_R_RTL_SHIFT 11 +#define OMAP44XX_R_RTL_MASK (0x1f << 11) +#define OMAP44XX_X_MAJOR_SHIFT 8 +#define OMAP44XX_X_MAJOR_MASK (0x7 << 8) +#define OMAP44XX_CUSTOM_SHIFT 6 +#define OMAP44XX_CUSTOM_MASK (0x3 << 6) +#define OMAP44XX_Y_MINOR_SHIFT 0 +#define OMAP44XX_Y_MINOR_MASK (0x3f << 0) + +/* DMM_HWINFO */ +#define OMAP44XX_ROBIN_CNT_SHIFT 16 +#define OMAP44XX_ROBIN_CNT_MASK (0xf << 16) +#define OMAP44XX_ELLA_CNT_SHIFT 8 +#define OMAP44XX_ELLA_CNT_MASK (0xf << 8) +#define OMAP44XX_TILER_CNT_SHIFT 0 +#define OMAP44XX_TILER_CNT_MASK (0xf << 0) + +/* DMM_LISA_HWINFO */ +#define OMAP44XX_SDRC_CNT_SHIFT 8 +#define OMAP44XX_SDRC_CNT_MASK (0xf << 8) +#define OMAP44XX_SECTION_CNT_SHIFT 0 +#define OMAP44XX_SECTION_CNT_MASK (0x1f << 0) + +/* DMM_SYSCONFIG */ +#define OMAP44XX_IDLE_MODE_SHIFT 2 +#define OMAP44XX_IDLE_MODE_MASK (0x3 << 2) + +/* DMM_LISA_LOCK */ +#define OMAP44XX_LOCK_SHIFT 0 +#define OMAP44XX_LOCK_MASK (1 << 0) + +/* DMM_LISA_MAP */ +#define OMAP44XX_SYS_ADDR_SHIFT 24 +#define OMAP44XX_SYS_ADDR_MASK (0xff << 24) +#define OMAP44XX_SYS_SIZE_SHIFT 20 +#define OMAP44XX_SYS_SIZE_MASK (0x7 << 20) +#define OMAP44XX_SDRC_INTL_SHIFT 18 +#define OMAP44XX_SDRC_INTL_MASK (0x3 << 18) +#define OMAP44XX_SDRC_ADDRSPC_SHIFT 16 +#define OMAP44XX_SDRC_ADDRSPC_MASK (0x3 << 16) +#define OMAP44XX_SDRC_MAP_SHIFT 8 +#define OMAP44XX_SDRC_MAP_MASK (0x3 << 8) +#define OMAP44XX_SDRC_ADDR_SHIFT 0 +#define OMAP44XX_SDRC_ADDR_MASK (0xff << 0) + +/* DMM_TILER_HWINFO */ +#define OMAP44XX_OR_CNT_SHIFT 0 +#define OMAP44XX_OR_CNT_MASK (0x7f << 0) + +/* DMM_TILER_OR */ +#define OMAP44XX_W7_SHIFT 31 +#define OMAP44XX_W7_MASK (1 << 31) +#define OMAP44XX_OR7_SHIFT 28 +#define OMAP44XX_OR7_MASK (0x7 << 28) +#define OMAP44XX_W6_SHIFT 27 +#define OMAP44XX_W6_MASK (1 << 27) +#define OMAP44XX_OR6_SHIFT 24 +#define OMAP44XX_OR6_MASK (0x7 << 24) +#define OMAP44XX_W5_SHIFT 23 +#define OMAP44XX_W5_MASK (1 << 23) +#define OMAP44XX_OR5_SHIFT 20 +#define OMAP44XX_OR5_MASK (0x7 << 20) +#define OMAP44XX_W4_SHIFT 19 +#define OMAP44XX_W4_MASK (1 << 19) +#define OMAP44XX_OR4_SHIFT 16 +#define OMAP44XX_OR4_MASK (0x7 << 16) +#define OMAP44XX_W3_SHIFT 15 +#define OMAP44XX_W3_MASK (1 << 15) +#define OMAP44XX_OR3_SHIFT 12 +#define OMAP44XX_OR3_MASK (0x7 << 12) +#define OMAP44XX_W2_SHIFT 11 +#define OMAP44XX_W2_MASK (1 << 11) +#define OMAP44XX_OR2_SHIFT 8 +#define OMAP44XX_OR2_MASK (0x7 << 8) +#define OMAP44XX_W1_SHIFT 7 +#define OMAP44XX_W1_MASK (1 << 7) +#define OMAP44XX_OR1_SHIFT 4 +#define OMAP44XX_OR1_MASK (0x7 << 4) +#define OMAP44XX_W0_SHIFT 3 +#define OMAP44XX_W0_MASK (1 << 3) +#define OMAP44XX_OR0_SHIFT 0 +#define OMAP44XX_OR0_MASK (0x7 << 0) + +/* DMM_PAT_HWINFO */ +#define OMAP44XX_ENGINE_CNT_SHIFT 24 +#define OMAP44XX_ENGINE_CNT_MASK (0x1f << 24) +#define OMAP44XX_LUT_CNT_SHIFT 16 +#define OMAP44XX_LUT_CNT_MASK (0x1f << 16) +#define OMAP44XX_VIEW_MAP_CNT_SHIFT 8 +#define OMAP44XX_VIEW_MAP_CNT_MASK (0xf << 8) +#define OMAP44XX_VIEW_CNT_SHIFT 0 +#define OMAP44XX_VIEW_CNT_MASK (0x7f << 0) + +/* DMM_PAT_GEOMETRY */ +#define OMAP44XX_CONT_HGHT_SHIFT 24 +#define OMAP44XX_CONT_HGHT_MASK (0x7 << 24) +#define OMAP44XX_CONT_WDTH_SHIFT 16 +#define OMAP44XX_CONT_WDTH_MASK (0xf << 16) +#define OMAP44XX_ADDR_RANGE_SHIFT 8 +#define OMAP44XX_ADDR_RANGE_MASK (0x3f << 8) +#define OMAP44XX_PAGE_SZ_SHIFT 0 +#define OMAP44XX_PAGE_SZ_MASK (0x1f << 0) + +/* DMM_PAT_CONFIG */ +#define OMAP44XX_MODE3_SHIFT 3 +#define OMAP44XX_MODE3_MASK (1 << 3) +#define OMAP44XX_MODE2_SHIFT 2 +#define OMAP44XX_MODE2_MASK (1 << 2) +#define OMAP44XX_MODE1_SHIFT 1 +#define OMAP44XX_MODE1_MASK (1 << 1) +#define OMAP44XX_MODE0_SHIFT 0 +#define OMAP44XX_MODE0_MASK (1 << 0) + +/* DMM_PAT_VIEW */ +#define OMAP44XX_V7_SHIFT 28 +#define OMAP44XX_V7_MASK (0x3 << 28) +#define OMAP44XX_V6_SHIFT 24 +#define OMAP44XX_V6_MASK (0x3 << 24) +#define OMAP44XX_V5_SHIFT 20 +#define OMAP44XX_V5_MASK (0x3 << 20) +#define OMAP44XX_V4_SHIFT 16 +#define OMAP44XX_V4_MASK (0x3 << 16) +#define OMAP44XX_V3_SHIFT 12 +#define OMAP44XX_V3_MASK (0x3 << 12) +#define OMAP44XX_V2_SHIFT 8 +#define OMAP44XX_V2_MASK (0x3 << 8) +#define OMAP44XX_V1_SHIFT 4 +#define OMAP44XX_V1_MASK (0x3 << 4) +#define OMAP44XX_V0_SHIFT 0 +#define OMAP44XX_V0_MASK (0x3 << 0) + +/* DMM_PAT_VIEW_MAP */ +#define OMAP44XX_ACCESS_PAGE_SHIFT 31 +#define OMAP44XX_ACCESS_PAGE_MASK (1 << 31) +#define OMAP44XX_CONT_PAGE_SHIFT 24 +#define OMAP44XX_CONT_PAGE_MASK (0xf << 24) +#define OMAP44XX_ACCESS_32_SHIFT 23 +#define OMAP44XX_ACCESS_32_MASK (1 << 23) +#define OMAP44XX_CONT_32_SHIFT 16 +#define OMAP44XX_CONT_32_MASK (0xf << 16) +#define OMAP44XX_ACCESS_16_SHIFT 15 +#define OMAP44XX_ACCESS_16_MASK (1 << 15) +#define OMAP44XX_CONT_16_SHIFT 8 +#define OMAP44XX_CONT_16_MASK (0xf << 8) +#define OMAP44XX_ACCESS_8_SHIFT 7 +#define OMAP44XX_ACCESS_8_MASK (1 << 7) +#define OMAP44XX_CONT_8_SHIFT 0 +#define OMAP44XX_CONT_8_MASK (0xf << 0) + +/* DMM_PAT_VIEW_MAP_BASE */ +#define OMAP44XX_BASE_ADDR_SHIFT 31 +#define OMAP44XX_BASE_ADDR_MASK (1 << 31) + +/* DMM_PAT_IRQ_EOI */ +#define OMAP44XX_EOI_SHIFT 0 +#define OMAP44XX_EOI_MASK (1 << 0) + +/* DMM_PAT_IRQSTATUS_RAW */ +#define OMAP44XX_ERR_LUT_MISS3_SHIFT 31 +#define OMAP44XX_ERR_LUT_MISS3_MASK (1 << 31) +#define OMAP44XX_ERR_UPD_DATA3_SHIFT 30 +#define OMAP44XX_ERR_UPD_DATA3_MASK (1 << 30) +#define OMAP44XX_ERR_UPD_CTRL3_SHIFT 29 +#define OMAP44XX_ERR_UPD_CTRL3_MASK (1 << 29) +#define OMAP44XX_ERR_UPD_AREA3_SHIFT 28 +#define OMAP44XX_ERR_UPD_AREA3_MASK (1 << 28) +#define OMAP44XX_ERR_INV_DATA3_SHIFT 27 +#define OMAP44XX_ERR_INV_DATA3_MASK (1 << 27) +#define OMAP44XX_ERR_INV_DSC3_SHIFT 26 +#define OMAP44XX_ERR_INV_DSC3_MASK (1 << 26) +#define OMAP44XX_FILL_LST3_SHIFT 25 +#define OMAP44XX_FILL_LST3_MASK (1 << 25) +#define OMAP44XX_FILL_DSC3_SHIFT 24 +#define OMAP44XX_FILL_DSC3_MASK (1 << 24) +#define OMAP44XX_ERR_LUT_MISS2_SHIFT 23 +#define OMAP44XX_ERR_LUT_MISS2_MASK (1 << 23) +#define OMAP44XX_ERR_UPD_DATA2_SHIFT 22 +#define OMAP44XX_ERR_UPD_DATA2_MASK (1 << 22) +#define OMAP44XX_ERR_UPD_CTRL2_SHIFT 21 +#define OMAP44XX_ERR_UPD_CTRL2_MASK (1 << 21) +#define OMAP44XX_ERR_UPD_AREA2_SHIFT 20 +#define OMAP44XX_ERR_UPD_AREA2_MASK (1 << 20) +#define OMAP44XX_ERR_INV_DATA2_SHIFT 19 +#define OMAP44XX_ERR_INV_DATA2_MASK (1 << 19) +#define OMAP44XX_ERR_INV_DSC2_SHIFT 18 +#define OMAP44XX_ERR_INV_DSC2_MASK (1 << 18) +#define OMAP44XX_FILL_LST2_SHIFT 17 +#define OMAP44XX_FILL_LST2_MASK (1 << 17) +#define OMAP44XX_FILL_DSC2_SHIFT 16 +#define OMAP44XX_FILL_DSC2_MASK (1 << 16) +#define OMAP44XX_ERR_LUT_MISS1_SHIFT 15 +#define OMAP44XX_ERR_LUT_MISS1_MASK (1 << 15) +#define OMAP44XX_ERR_UPD_DATA1_SHIFT 14 +#define OMAP44XX_ERR_UPD_DATA1_MASK (1 << 14) +#define OMAP44XX_ERR_UPD_CTRL1_SHIFT 13 +#define OMAP44XX_ERR_UPD_CTRL1_MASK (1 << 13) +#define OMAP44XX_ERR_UPD_AREA1_SHIFT 12 +#define OMAP44XX_ERR_UPD_AREA1_MASK (1 << 12) +#define OMAP44XX_ERR_INV_DATA1_SHIFT 11 +#define OMAP44XX_ERR_INV_DATA1_MASK (1 << 11) +#define OMAP44XX_ERR_INV_DSC1_SHIFT 10 +#define OMAP44XX_ERR_INV_DSC1_MASK (1 << 10) +#define OMAP44XX_FILL_LST1_SHIFT 9 +#define OMAP44XX_FILL_LST1_MASK (1 << 9) +#define OMAP44XX_FILL_DSC1_SHIFT 8 +#define OMAP44XX_FILL_DSC1_MASK (1 << 8) +#define OMAP44XX_ERR_LUT_MISS0_SHIFT 7 +#define OMAP44XX_ERR_LUT_MISS0_MASK (1 << 7) +#define OMAP44XX_ERR_UPD_DATA0_SHIFT 6 +#define OMAP44XX_ERR_UPD_DATA0_MASK (1 << 6) +#define OMAP44XX_ERR_UPD_CTRL0_SHIFT 5 +#define OMAP44XX_ERR_UPD_CTRL0_MASK (1 << 5) +#define OMAP44XX_ERR_UPD_AREA0_SHIFT 4 +#define OMAP44XX_ERR_UPD_AREA0_MASK (1 << 4) +#define OMAP44XX_ERR_INV_DATA0_SHIFT 3 +#define OMAP44XX_ERR_INV_DATA0_MASK (1 << 3) +#define OMAP44XX_ERR_INV_DSC0_SHIFT 2 +#define OMAP44XX_ERR_INV_DSC0_MASK (1 << 2) +#define OMAP44XX_FILL_LST0_SHIFT 1 +#define OMAP44XX_FILL_LST0_MASK (1 << 1) +#define OMAP44XX_FILL_DSC0_SHIFT 0 +#define OMAP44XX_FILL_DSC0_MASK (1 << 0) + +/* DMM_PAT_IRQSTATUS */ + +/* DMM_PAT_IRQENABLE_SET */ + +/* DMM_PAT_IRQENABLE_CLR */ + +/* DMM_PAT_STATUS */ +#define OMAP44XX_CNT_SHIFT 16 +#define OMAP44XX_CNT_MASK (0x1ff << 16) +#define OMAP44XX_ERROR_SHIFT 10 +#define OMAP44XX_ERROR_MASK (0x3f << 10) +#define OMAP44XX_BYPASSED_SHIFT 7 +#define OMAP44XX_BYPASSED_MASK (1 << 7) +#define OMAP44XX_LINKED_SHIFT 4 +#define OMAP44XX_LINKED_MASK (1 << 4) +#define OMAP44XX_DONE_SHIFT 3 +#define OMAP44XX_DONE_MASK (1 << 3) +#define OMAP44XX_RUN_SHIFT 2 +#define OMAP44XX_RUN_MASK (1 << 2) +#define OMAP44XX_VALID_SHIFT 1 +#define OMAP44XX_VALID_MASK (1 << 1) +#define OMAP44XX_READY_SHIFT 0 +#define OMAP44XX_READY_MASK (1 << 0) + +/* DMM_PAT_DESCR */ +#define OMAP44XX_ADDR_SHIFT 4 +#define OMAP44XX_ADDR_MASK (0xfffffff << 4) + +/* DMM_PAT_AREA */ +#define OMAP44XX_Y1_SHIFT 24 +#define OMAP44XX_Y1_MASK (0x7f << 24) +#define OMAP44XX_X1_SHIFT 16 +#define OMAP44XX_X1_MASK (0xff << 16) +#define OMAP44XX_Y0_SHIFT 8 +#define OMAP44XX_Y0_MASK (0x7f << 8) +#define OMAP44XX_X0_SHIFT 0 +#define OMAP44XX_X0_MASK (0xff << 0) + +/* DMM_PAT_CTRL */ +#define OMAP44XX_INITIATOR_SHIFT 28 +#define OMAP44XX_INITIATOR_MASK (0xf << 28) +#define OMAP44XX_SYNC_SHIFT 16 +#define OMAP44XX_SYNC_MASK (1 << 16) +#define OMAP44XX_DIRECTION_SHIFT 4 +#define OMAP44XX_DIRECTION_MASK (0x7 << 4) +#define OMAP44XX_START_SHIFT 0 +#define OMAP44XX_START_MASK (1 << 0) + +/* DMM_PAT_DATA */ + +/* DMM_PEG_HWINFO */ +#define OMAP44XX_PRIO_CNT_SHIFT 0 +#define OMAP44XX_PRIO_CNT_MASK (0x7f << 0) + +/* DMM_PEG_PRIO */ +#define OMAP44XX_P7_SHIFT 28 +#define OMAP44XX_P7_MASK (0x7 << 28) +#define OMAP44XX_P6_SHIFT 24 +#define OMAP44XX_P6_MASK (0x7 << 24) +#define OMAP44XX_P5_SHIFT 20 +#define OMAP44XX_P5_MASK (0x7 << 20) +#define OMAP44XX_P4_SHIFT 16 +#define OMAP44XX_P4_MASK (0x7 << 16) +#define OMAP44XX_P3_SHIFT 12 +#define OMAP44XX_P3_MASK (0x7 << 12) +#define OMAP44XX_P2_SHIFT 8 +#define OMAP44XX_P2_MASK (0x7 << 8) +#define OMAP44XX_P1_SHIFT 4 +#define OMAP44XX_P1_MASK (0x7 << 4) +#define OMAP44XX_P0_SHIFT 0 +#define OMAP44XX_P0_MASK (0x7 << 0) + +/* DMM_PEG_PRIO_PAT */ +#define OMAP44XX_W_PAT_SHIFT 3 +#define OMAP44XX_W_PAT_MASK (1 << 3) +#define OMAP44XX_P_PAT_SHIFT 0 +#define OMAP44XX_P_PAT_MASK (0x7 << 0) +#endif diff --git a/arch/arm/mach-omap2/include/mach/dmm.h b/arch/arm/mach-omap2/include/mach/dmm.h new file mode 100644 index 0000000..3567b6f9 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/dmm.h @@ -0,0 +1,164 @@ +/* + * dmm.h + * + * DMM driver support functions for TI DMM-TILER hardware block. + * + * Author: David Sin <davidsin@ti.com> + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DMM_H +#define DMM_H + +#define DMM_BASE 0x4E000000 +#define DMM_SIZE 0x800 + +#define DMM_REVISION 0x000 +#define DMM_HWINFO 0x004 +#define DMM_LISA_HWINFO 0x008 +#define DMM_DMM_SYSCONFIG 0x010 +#define DMM_LISA_LOCK 0x01C +#define DMM_LISA_MAP__0 0x040 +#define DMM_LISA_MAP__1 0x044 +#define DMM_TILER_HWINFO 0x208 +#define DMM_TILER_OR__0 0x220 +#define DMM_TILER_OR__1 0x224 +#define DMM_PAT_HWINFO 0x408 +#define DMM_PAT_GEOMETRY 0x40C +#define DMM_PAT_CONFIG 0x410 +#define DMM_PAT_VIEW__0 0x420 +#define DMM_PAT_VIEW__1 0x424 +#define DMM_PAT_VIEW_MAP__0 0x440 +#define DMM_PAT_VIEW_MAP_BASE 0x460 +#define DMM_PAT_IRQ_EOI 0x478 +#define DMM_PAT_IRQSTATUS_RAW 0x480 +#define DMM_PAT_IRQSTATUS 0x490 +#define DMM_PAT_IRQENABLE_SET 0x4A0 +#define DMM_PAT_IRQENABLE_CLR 0x4B0 +#define DMM_PAT_STATUS__0 0x4C0 +#define DMM_PAT_STATUS__1 0x4C4 +#define DMM_PAT_STATUS__2 0x4C8 +#define DMM_PAT_STATUS__3 0x4CC +#define DMM_PAT_DESCR__0 0x500 +#define DMM_PAT_AREA__0 0x504 +#define DMM_PAT_CTRL__0 0x508 +#define DMM_PAT_DATA__0 0x50C +#define DMM_PEG_HWINFO 0x608 +#define DMM_PEG_PRIO 0x620 +#define DMM_PEG_PRIO_PAT 0x640 + +/** + * PAT refill programming mode. + */ +enum pat_mode { + MANUAL, + AUTO +}; + +/** + * Area definition for DMM physical address translator. + */ +struct pat_area { + s32 x0:8; + s32 y0:8; + s32 x1:8; + s32 y1:8; +}; + +/** + * DMM physical address translator control. + */ +struct pat_ctrl { + s32 start:4; + s32 dir:4; + s32 lut_id:8; + s32 sync:12; + s32 ini:4; +}; + +/** + * PAT descriptor. + */ +struct pat { + struct pat *next; + struct pat_area area; + struct pat_ctrl ctrl; + u32 data; +}; + +/** + * DMM device data + */ +struct dmm { + void __iomem *base; +}; + +/** + * Create and initialize the physical address translator. + * @param id PAT id + * @return pointer to device data + */ +struct dmm *dmm_pat_init(u32 id); + +/** + * Program the physical address translator. + * @param dmm Device data + * @param desc PAT descriptor + * @param mode programming mode + * @return an error status. + */ +s32 dmm_pat_refill(struct dmm *dmm, struct pat *desc, enum pat_mode mode); + +/** + * Clean up the physical address translator. + * @param dmm Device data + * @return an error status. + */ +void dmm_pat_release(struct dmm *dmm); + +/** + * DMM Platform Device Data structure + * + */ +struct omap_dmm_platform_data { + const char *oh_name; + void __iomem *base; + int irq; +}; + +/** + * Init function for use in board init file + * + */ +void omap_dmm_init(void); + +#endif diff --git a/arch/arm/mach-omap2/include/mach/emif-44xx.h b/arch/arm/mach-omap2/include/mach/emif-44xx.h new file mode 100644 index 0000000..58a80f2 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/emif-44xx.h @@ -0,0 +1,526 @@ +/* + * OMAP44xx EMIF registers and bitfields + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * Benoit Cousson (b-cousson@ti.com) + * Santosh Shilimkar (santosh.shilimkar@ti.com) + * + * This file is automatically generated from the OMAP hardware databases. + * We respectfully ask that any modifications to this file be coordinated + * with the public linux-omap@vger.kernel.org mailing list and the + * authors above to ensure that the autogeneration scripts are kept + * up-to-date with the file contents. + * + * 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. + */ + +#ifndef __ARCH_ARM_MACH_OMAP2_EMIF_44XX_H +#define __ARCH_ARM_MACH_OMAP2_EMIF_44XX_H + + +/* Base address */ +#define OMAP44XX_EMIF1 0x4c000000 +#define OMAP44XX_EMIF2 0x4d000000 + +/* Registers offset */ +#define OMAP44XX_EMIF_MOD_ID_REV 0x0000 +#define OMAP44XX_EMIF_STATUS 0x0004 +#define OMAP44XX_EMIF_SDRAM_CONFIG 0x0008 +#define OMAP44XX_EMIF_SDRAM_CONFIG_2 0x000c +#define OMAP44XX_EMIF_SDRAM_REF_CTRL 0x0010 +#define OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW 0x0014 +#define OMAP44XX_EMIF_SDRAM_TIM_1 0x0018 +#define OMAP44XX_EMIF_SDRAM_TIM_1_SHDW 0x001c +#define OMAP44XX_EMIF_SDRAM_TIM_2 0x0020 +#define OMAP44XX_EMIF_SDRAM_TIM_2_SHDW 0x0024 +#define OMAP44XX_EMIF_SDRAM_TIM_3 0x0028 +#define OMAP44XX_EMIF_SDRAM_TIM_3_SHDW 0x002c +#define OMAP44XX_EMIF_LPDDR2_NVM_TIM 0x0030 +#define OMAP44XX_EMIF_LPDDR2_NVM_TIM_SHDW 0x0034 +#define OMAP44XX_EMIF_PWR_MGMT_CTRL 0x0038 +#define OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW 0x003c +#define OMAP44XX_EMIF_LPDDR2_MODE_REG_DATA 0x0040 +#define OMAP44XX_EMIF_LPDDR2_MODE_REG_CFG 0x0050 +#define OMAP44XX_EMIF_OCP_CONFIG 0x0054 +#define OMAP44XX_EMIF_OCP_CFG_VAL_1 0x0058 +#define OMAP44XX_EMIF_OCP_CFG_VAL_2 0x005c +#define OMAP44XX_EMIF_IODFT_TLGC 0x0060 +#define OMAP44XX_EMIF_IODFT_CTRL_MISR_RSLT 0x0064 +#define OMAP44XX_EMIF_IODFT_ADDR_MISR_RSLT 0x0068 +#define OMAP44XX_EMIF_IODFT_DATA_MISR_RSLT_1 0x006c +#define OMAP44XX_EMIF_IODFT_DATA_MISR_RSLT_2 0x0070 +#define OMAP44XX_EMIF_IODFT_DATA_MISR_RSLT_3 0x0074 +#define OMAP44XX_EMIF_PERF_CNT_1 0x0080 +#define OMAP44XX_EMIF_PERF_CNT_2 0x0084 +#define OMAP44XX_EMIF_PERF_CNT_CFG 0x0088 +#define OMAP44XX_EMIF_PERF_CNT_SEL 0x008c +#define OMAP44XX_EMIF_PERF_CNT_TIM 0x0090 +#define OMAP44XX_EMIF_READ_IDLE_CTRL 0x0098 +#define OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW 0x009c +#define OMAP44XX_EMIF_IRQ_EOI 0x00a0 +#define OMAP44XX_EMIF_IRQSTATUS_RAW_SYS 0x00a4 +#define OMAP44XX_EMIF_IRQSTATUS_RAW_LL 0x00a8 +#define OMAP44XX_EMIF_IRQSTATUS_SYS 0x00ac +#define OMAP44XX_EMIF_IRQSTATUS_LL 0x00b0 +#define OMAP44XX_EMIF_IRQENABLE_SET_SYS 0x00b4 +#define OMAP44XX_EMIF_IRQENABLE_SET_LL 0x00b8 +#define OMAP44XX_EMIF_IRQENABLE_CLR_SYS 0x00bc +#define OMAP44XX_EMIF_IRQENABLE_CLR_LL 0x00c0 +#define OMAP44XX_EMIF_ZQ_CONFIG 0x00c8 +#define OMAP44XX_EMIF_TEMP_ALERT_CONFIG 0x00cc +#define OMAP44XX_EMIF_OCP_ERR_LOG 0x00d0 +#define OMAP44XX_EMIF_DDR_PHY_CTRL_1 0x00e4 +#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW 0x00e8 +#define OMAP44XX_EMIF_DDR_PHY_CTRL_2 0x00ec + +/* Registers shifts and masks */ + +/* EMIF_MOD_ID_REV */ +#define OMAP44XX_REG_SCHEME_SHIFT 30 +#define OMAP44XX_REG_SCHEME_MASK (0x3 << 30) +#define OMAP44XX_REG_MODULE_ID_SHIFT 16 +#define OMAP44XX_REG_MODULE_ID_MASK (0xfff << 16) +#define OMAP44XX_REG_RTL_VERSION_SHIFT 11 +#define OMAP44XX_REG_RTL_VERSION_MASK (0x1f << 11) +#define OMAP44XX_REG_MAJOR_REVISION_SHIFT 8 +#define OMAP44XX_REG_MAJOR_REVISION_MASK (0x7 << 8) +#define OMAP44XX_REG_MINOR_REVISION_SHIFT 0 +#define OMAP44XX_REG_MINOR_REVISION_MASK (0x3f << 0) + +/* STATUS */ +#define OMAP44XX_REG_BE_SHIFT 31 +#define OMAP44XX_REG_BE_MASK (1 << 31) +#define OMAP44XX_REG_DUAL_CLK_MODE_SHIFT 30 +#define OMAP44XX_REG_DUAL_CLK_MODE_MASK (1 << 30) +#define OMAP44XX_REG_FAST_INIT_SHIFT 29 +#define OMAP44XX_REG_FAST_INIT_MASK (1 << 29) +#define OMAP44XX_REG_PHY_DLL_READY_SHIFT 2 +#define OMAP44XX_REG_PHY_DLL_READY_MASK (1 << 2) + +/* SDRAM_CONFIG */ +#define OMAP44XX_REG_SDRAM_TYPE_SHIFT 29 +#define OMAP44XX_REG_SDRAM_TYPE_MASK (0x7 << 29) +#define OMAP44XX_REG_IBANK_POS_SHIFT 27 +#define OMAP44XX_REG_IBANK_POS_MASK (0x3 << 27) +#define OMAP44XX_REG_DDR_TERM_SHIFT 24 +#define OMAP44XX_REG_DDR_TERM_MASK (0x7 << 24) +#define OMAP44XX_REG_DDR2_DDQS_SHIFT 23 +#define OMAP44XX_REG_DDR2_DDQS_MASK (1 << 23) +#define OMAP44XX_REG_DYN_ODT_SHIFT 21 +#define OMAP44XX_REG_DYN_ODT_MASK (0x3 << 21) +#define OMAP44XX_REG_DDR_DISABLE_DLL_SHIFT 20 +#define OMAP44XX_REG_DDR_DISABLE_DLL_MASK (1 << 20) +#define OMAP44XX_REG_SDRAM_DRIVE_SHIFT 18 +#define OMAP44XX_REG_SDRAM_DRIVE_MASK (0x3 << 18) +#define OMAP44XX_REG_CWL_SHIFT 16 +#define OMAP44XX_REG_CWL_MASK (0x3 << 16) +#define OMAP44XX_REG_NARROW_MODE_SHIFT 14 +#define OMAP44XX_REG_NARROW_MODE_MASK (0x3 << 14) +#define OMAP44XX_REG_CL_SHIFT 10 +#define OMAP44XX_REG_CL_MASK (0xf << 10) +#define OMAP44XX_REG_ROWSIZE_SHIFT 7 +#define OMAP44XX_REG_ROWSIZE_MASK (0x7 << 7) +#define OMAP44XX_REG_IBANK_SHIFT 4 +#define OMAP44XX_REG_IBANK_MASK (0x7 << 4) +#define OMAP44XX_REG_EBANK_SHIFT 3 +#define OMAP44XX_REG_EBANK_MASK (1 << 3) +#define OMAP44XX_REG_PAGESIZE_SHIFT 0 +#define OMAP44XX_REG_PAGESIZE_MASK (0x7 << 0) + +/* SDRAM_CONFIG_2 */ +#define OMAP44XX_REG_CS1NVMEN_SHIFT 30 +#define OMAP44XX_REG_CS1NVMEN_MASK (1 << 30) +#define OMAP44XX_REG_EBANK_POS_SHIFT 27 +#define OMAP44XX_REG_EBANK_POS_MASK (1 << 27) +#define OMAP44XX_REG_RDBNUM_SHIFT 4 +#define OMAP44XX_REG_RDBNUM_MASK (0x3 << 4) +#define OMAP44XX_REG_RDBSIZE_SHIFT 0 +#define OMAP44XX_REG_RDBSIZE_MASK (0x7 << 0) + +/* SDRAM_REF_CTRL */ +#define OMAP44XX_REG_INITREF_DIS_SHIFT 31 +#define OMAP44XX_REG_INITREF_DIS_MASK (1 << 31) +#define OMAP44XX_REG_SRT_SHIFT 29 +#define OMAP44XX_REG_SRT_MASK (1 << 29) +#define OMAP44XX_REG_ASR_SHIFT 28 +#define OMAP44XX_REG_ASR_MASK (1 << 28) +#define OMAP44XX_REG_PASR_SHIFT 24 +#define OMAP44XX_REG_PASR_MASK (0x7 << 24) +#define OMAP44XX_REG_REFRESH_RATE_SHIFT 0 +#define OMAP44XX_REG_REFRESH_RATE_MASK (0xffff << 0) + +/* SDRAM_REF_CTRL_SHDW */ +#define OMAP44XX_REG_REFRESH_RATE_SHDW_SHIFT 0 +#define OMAP44XX_REG_REFRESH_RATE_SHDW_MASK (0xffff << 0) + +/* SDRAM_TIM_1 */ +#define OMAP44XX_REG_T_RP_SHIFT 25 +#define OMAP44XX_REG_T_RP_MASK (0xf << 25) +#define OMAP44XX_REG_T_RCD_SHIFT 21 +#define OMAP44XX_REG_T_RCD_MASK (0xf << 21) +#define OMAP44XX_REG_T_WR_SHIFT 17 +#define OMAP44XX_REG_T_WR_MASK (0xf << 17) +#define OMAP44XX_REG_T_RAS_SHIFT 12 +#define OMAP44XX_REG_T_RAS_MASK (0x1f << 12) +#define OMAP44XX_REG_T_RC_SHIFT 6 +#define OMAP44XX_REG_T_RC_MASK (0x3f << 6) +#define OMAP44XX_REG_T_RRD_SHIFT 3 +#define OMAP44XX_REG_T_RRD_MASK (0x7 << 3) +#define OMAP44XX_REG_T_WTR_SHIFT 0 +#define OMAP44XX_REG_T_WTR_MASK (0x7 << 0) + +/* SDRAM_TIM_1_SHDW */ +#define OMAP44XX_REG_T_RP_SHDW_SHIFT 25 +#define OMAP44XX_REG_T_RP_SHDW_MASK (0xf << 25) +#define OMAP44XX_REG_T_RCD_SHDW_SHIFT 21 +#define OMAP44XX_REG_T_RCD_SHDW_MASK (0xf << 21) +#define OMAP44XX_REG_T_WR_SHDW_SHIFT 17 +#define OMAP44XX_REG_T_WR_SHDW_MASK (0xf << 17) +#define OMAP44XX_REG_T_RAS_SHDW_SHIFT 12 +#define OMAP44XX_REG_T_RAS_SHDW_MASK (0x1f << 12) +#define OMAP44XX_REG_T_RC_SHDW_SHIFT 6 +#define OMAP44XX_REG_T_RC_SHDW_MASK (0x3f << 6) +#define OMAP44XX_REG_T_RRD_SHDW_SHIFT 3 +#define OMAP44XX_REG_T_RRD_SHDW_MASK (0x7 << 3) +#define OMAP44XX_REG_T_WTR_SHDW_SHIFT 0 +#define OMAP44XX_REG_T_WTR_SHDW_MASK (0x7 << 0) + +/* SDRAM_TIM_2 */ +#define OMAP44XX_REG_T_XP_SHIFT 28 +#define OMAP44XX_REG_T_XP_MASK (0x7 << 28) +#define OMAP44XX_REG_T_ODT_SHIFT 25 +#define OMAP44XX_REG_T_ODT_MASK (0x7 << 25) +#define OMAP44XX_REG_T_XSNR_SHIFT 16 +#define OMAP44XX_REG_T_XSNR_MASK (0x1ff << 16) +#define OMAP44XX_REG_T_XSRD_SHIFT 6 +#define OMAP44XX_REG_T_XSRD_MASK (0x3ff << 6) +#define OMAP44XX_REG_T_RTP_SHIFT 3 +#define OMAP44XX_REG_T_RTP_MASK (0x7 << 3) +#define OMAP44XX_REG_T_CKE_SHIFT 0 +#define OMAP44XX_REG_T_CKE_MASK (0x7 << 0) + +/* SDRAM_TIM_2_SHDW */ +#define OMAP44XX_REG_T_XP_SHDW_SHIFT 28 +#define OMAP44XX_REG_T_XP_SHDW_MASK (0x7 << 28) +#define OMAP44XX_REG_T_ODT_SHDW_SHIFT 25 +#define OMAP44XX_REG_T_ODT_SHDW_MASK (0x7 << 25) +#define OMAP44XX_REG_T_XSNR_SHDW_SHIFT 16 +#define OMAP44XX_REG_T_XSNR_SHDW_MASK (0x1ff << 16) +#define OMAP44XX_REG_T_XSRD_SHDW_SHIFT 6 +#define OMAP44XX_REG_T_XSRD_SHDW_MASK (0x3ff << 6) +#define OMAP44XX_REG_T_RTP_SHDW_SHIFT 3 +#define OMAP44XX_REG_T_RTP_SHDW_MASK (0x7 << 3) +#define OMAP44XX_REG_T_CKE_SHDW_SHIFT 0 +#define OMAP44XX_REG_T_CKE_SHDW_MASK (0x7 << 0) + +/* SDRAM_TIM_3 */ +#define OMAP44XX_REG_T_CKESR_SHIFT 21 +#define OMAP44XX_REG_T_CKESR_MASK (0x7 << 21) +#define OMAP44XX_REG_ZQ_ZQCS_SHIFT 15 +#define OMAP44XX_REG_ZQ_ZQCS_MASK (0x3f << 15) +#define OMAP44XX_REG_T_TDQSCKMAX_SHIFT 13 +#define OMAP44XX_REG_T_TDQSCKMAX_MASK (0x3 << 13) +#define OMAP44XX_REG_T_RFC_SHIFT 4 +#define OMAP44XX_REG_T_RFC_MASK (0x1ff << 4) +#define OMAP44XX_REG_T_RAS_MAX_SHIFT 0 +#define OMAP44XX_REG_T_RAS_MAX_MASK (0xf << 0) + +/* SDRAM_TIM_3_SHDW */ +#define OMAP44XX_REG_T_CKESR_SHDW_SHIFT 21 +#define OMAP44XX_REG_T_CKESR_SHDW_MASK (0x7 << 21) +#define OMAP44XX_REG_ZQ_ZQCS_SHDW_SHIFT 15 +#define OMAP44XX_REG_ZQ_ZQCS_SHDW_MASK (0x3f << 15) +#define OMAP44XX_REG_T_TDQSCKMAX_SHDW_SHIFT 13 +#define OMAP44XX_REG_T_TDQSCKMAX_SHDW_MASK (0x3 << 13) +#define OMAP44XX_REG_T_RFC_SHDW_SHIFT 4 +#define OMAP44XX_REG_T_RFC_SHDW_MASK (0x1ff << 4) +#define OMAP44XX_REG_T_RAS_MAX_SHDW_SHIFT 0 +#define OMAP44XX_REG_T_RAS_MAX_SHDW_MASK (0xf << 0) + +/* LPDDR2_NVM_TIM */ +#define OMAP44XX_REG_NVM_T_XP_SHIFT 28 +#define OMAP44XX_REG_NVM_T_XP_MASK (0x7 << 28) +#define OMAP44XX_REG_NVM_T_WTR_SHIFT 24 +#define OMAP44XX_REG_NVM_T_WTR_MASK (0x7 << 24) +#define OMAP44XX_REG_NVM_T_RP_SHIFT 20 +#define OMAP44XX_REG_NVM_T_RP_MASK (0xf << 20) +#define OMAP44XX_REG_NVM_T_WRA_SHIFT 16 +#define OMAP44XX_REG_NVM_T_WRA_MASK (0xf << 16) +#define OMAP44XX_REG_NVM_T_RRD_SHIFT 8 +#define OMAP44XX_REG_NVM_T_RRD_MASK (0xff << 8) +#define OMAP44XX_REG_NVM_T_RCDMIN_SHIFT 0 +#define OMAP44XX_REG_NVM_T_RCDMIN_MASK (0xff << 0) + +/* LPDDR2_NVM_TIM_SHDW */ +#define OMAP44XX_REG_NVM_T_XP_SHDW_SHIFT 28 +#define OMAP44XX_REG_NVM_T_XP_SHDW_MASK (0x7 << 28) +#define OMAP44XX_REG_NVM_T_WTR_SHDW_SHIFT 24 +#define OMAP44XX_REG_NVM_T_WTR_SHDW_MASK (0x7 << 24) +#define OMAP44XX_REG_NVM_T_RP_SHDW_SHIFT 20 +#define OMAP44XX_REG_NVM_T_RP_SHDW_MASK (0xf << 20) +#define OMAP44XX_REG_NVM_T_WRA_SHDW_SHIFT 16 +#define OMAP44XX_REG_NVM_T_WRA_SHDW_MASK (0xf << 16) +#define OMAP44XX_REG_NVM_T_RRD_SHDW_SHIFT 8 +#define OMAP44XX_REG_NVM_T_RRD_SHDW_MASK (0xff << 8) +#define OMAP44XX_REG_NVM_T_RCDMIN_SHDW_SHIFT 0 +#define OMAP44XX_REG_NVM_T_RCDMIN_SHDW_MASK (0xff << 0) + +/* PWR_MGMT_CTRL */ +#define OMAP44XX_REG_PD_TIM_SHIFT 12 +#define OMAP44XX_REG_PD_TIM_MASK (0xf << 12) +#define OMAP44XX_REG_DPD_EN_SHIFT 11 +#define OMAP44XX_REG_DPD_EN_MASK (1 << 11) +#define OMAP44XX_REG_LP_MODE_SHIFT 8 +#define OMAP44XX_REG_LP_MODE_MASK (0x7 << 8) +#define OMAP44XX_REG_SR_TIM_SHIFT 4 +#define OMAP44XX_REG_SR_TIM_MASK (0xf << 4) +#define OMAP44XX_REG_CS_TIM_SHIFT 0 +#define OMAP44XX_REG_CS_TIM_MASK (0xf << 0) + +/* PWR_MGMT_CTRL_SHDW */ +#define OMAP44XX_REG_PD_TIM_SHDW_SHIFT 12 +#define OMAP44XX_REG_PD_TIM_SHDW_MASK (0xf << 12) +#define OMAP44XX_REG_SR_TIM_SHDW_SHIFT 4 +#define OMAP44XX_REG_SR_TIM_SHDW_MASK (0xf << 4) +#define OMAP44XX_REG_CS_TIM_SHDW_SHIFT 0 +#define OMAP44XX_REG_CS_TIM_SHDW_MASK (0xf << 0) + +/* LPDDR2_MODE_REG_DATA */ +#define OMAP44XX_REG_VALUE_0_SHIFT 0 +#define OMAP44XX_REG_VALUE_0_MASK (0x7f << 0) + +/* LPDDR2_MODE_REG_CFG */ +#define OMAP44XX_REG_CS_SHIFT 31 +#define OMAP44XX_REG_CS_MASK (1 << 31) +#define OMAP44XX_REG_REFRESH_EN_SHIFT 30 +#define OMAP44XX_REG_REFRESH_EN_MASK (1 << 30) +#define OMAP44XX_REG_ADDRESS_SHIFT 0 +#define OMAP44XX_REG_ADDRESS_MASK (0xff << 0) + +/* OCP_CONFIG */ +#define OMAP44XX_REG_SYS_THRESH_MAX_SHIFT 24 +#define OMAP44XX_REG_SYS_THRESH_MAX_MASK (0xf << 24) +#define OMAP44XX_REG_LL_THRESH_MAX_SHIFT 16 +#define OMAP44XX_REG_LL_THRESH_MAX_MASK (0xf << 16) +#define OMAP44XX_REG_PR_OLD_COUNT_SHIFT 0 +#define OMAP44XX_REG_PR_OLD_COUNT_MASK (0xff << 0) + +/* OCP_CFG_VAL_1 */ +#define OMAP44XX_REG_SYS_BUS_WIDTH_SHIFT 30 +#define OMAP44XX_REG_SYS_BUS_WIDTH_MASK (0x3 << 30) +#define OMAP44XX_REG_LL_BUS_WIDTH_SHIFT 28 +#define OMAP44XX_REG_LL_BUS_WIDTH_MASK (0x3 << 28) +#define OMAP44XX_REG_WR_FIFO_DEPTH_SHIFT 8 +#define OMAP44XX_REG_WR_FIFO_DEPTH_MASK (0xff << 8) +#define OMAP44XX_REG_CMD_FIFO_DEPTH_SHIFT 0 +#define OMAP44XX_REG_CMD_FIFO_DEPTH_MASK (0xff << 0) + +/* OCP_CFG_VAL_2 */ +#define OMAP44XX_REG_RREG_FIFO_DEPTH_SHIFT 16 +#define OMAP44XX_REG_RREG_FIFO_DEPTH_MASK (0xff << 16) +#define OMAP44XX_REG_RSD_FIFO_DEPTH_SHIFT 8 +#define OMAP44XX_REG_RSD_FIFO_DEPTH_MASK (0xff << 8) +#define OMAP44XX_REG_RCMD_FIFO_DEPTH_SHIFT 0 +#define OMAP44XX_REG_RCMD_FIFO_DEPTH_MASK (0xff << 0) + +/* IODFT_TLGC */ +#define OMAP44XX_REG_TLEC_SHIFT 16 +#define OMAP44XX_REG_TLEC_MASK (0xffff << 16) +#define OMAP44XX_REG_MT_SHIFT 14 +#define OMAP44XX_REG_MT_MASK (1 << 14) +#define OMAP44XX_REG_ACT_CAP_EN_SHIFT 13 +#define OMAP44XX_REG_ACT_CAP_EN_MASK (1 << 13) +#define OMAP44XX_REG_OPG_LD_SHIFT 12 +#define OMAP44XX_REG_OPG_LD_MASK (1 << 12) +#define OMAP44XX_REG_RESET_PHY_SHIFT 10 +#define OMAP44XX_REG_RESET_PHY_MASK (1 << 10) +#define OMAP44XX_REG_MMS_SHIFT 8 +#define OMAP44XX_REG_MMS_MASK (1 << 8) +#define OMAP44XX_REG_MC_SHIFT 4 +#define OMAP44XX_REG_MC_MASK (0x3 << 4) +#define OMAP44XX_REG_PC_SHIFT 1 +#define OMAP44XX_REG_PC_MASK (0x7 << 1) +#define OMAP44XX_REG_TM_SHIFT 0 +#define OMAP44XX_REG_TM_MASK (1 << 0) + +/* IODFT_CTRL_MISR_RSLT */ +#define OMAP44XX_REG_DQM_TLMR_SHIFT 16 +#define OMAP44XX_REG_DQM_TLMR_MASK (0x3ff << 16) +#define OMAP44XX_REG_CTL_TLMR_SHIFT 0 +#define OMAP44XX_REG_CTL_TLMR_MASK (0x7ff << 0) + +/* IODFT_ADDR_MISR_RSLT */ +#define OMAP44XX_REG_ADDR_TLMR_SHIFT 0 +#define OMAP44XX_REG_ADDR_TLMR_MASK (0x1fffff << 0) + +/* IODFT_DATA_MISR_RSLT_1 */ +#define OMAP44XX_REG_DATA_TLMR_31_0_SHIFT 0 +#define OMAP44XX_REG_DATA_TLMR_31_0_MASK (0xffffffff << 0) + +/* IODFT_DATA_MISR_RSLT_2 */ +#define OMAP44XX_REG_DATA_TLMR_63_32_SHIFT 0 +#define OMAP44XX_REG_DATA_TLMR_63_32_MASK (0xffffffff << 0) + +/* IODFT_DATA_MISR_RSLT_3 */ +#define OMAP44XX_REG_DATA_TLMR_66_64_SHIFT 0 +#define OMAP44XX_REG_DATA_TLMR_66_64_MASK (0x7 << 0) + +/* PERF_CNT_1 */ +#define OMAP44XX_REG_COUNTER1_SHIFT 0 +#define OMAP44XX_REG_COUNTER1_MASK (0xffffffff << 0) + +/* PERF_CNT_2 */ +#define OMAP44XX_REG_COUNTER2_SHIFT 0 +#define OMAP44XX_REG_COUNTER2_MASK (0xffffffff << 0) + +/* PERF_CNT_CFG */ +#define OMAP44XX_REG_CNTR2_MCONNID_EN_SHIFT 31 +#define OMAP44XX_REG_CNTR2_MCONNID_EN_MASK (1 << 31) +#define OMAP44XX_REG_CNTR2_REGION_EN_SHIFT 30 +#define OMAP44XX_REG_CNTR2_REGION_EN_MASK (1 << 30) +#define OMAP44XX_REG_CNTR2_CFG_SHIFT 16 +#define OMAP44XX_REG_CNTR2_CFG_MASK (0xf << 16) +#define OMAP44XX_REG_CNTR1_MCONNID_EN_SHIFT 15 +#define OMAP44XX_REG_CNTR1_MCONNID_EN_MASK (1 << 15) +#define OMAP44XX_REG_CNTR1_REGION_EN_SHIFT 14 +#define OMAP44XX_REG_CNTR1_REGION_EN_MASK (1 << 14) +#define OMAP44XX_REG_CNTR1_CFG_SHIFT 0 +#define OMAP44XX_REG_CNTR1_CFG_MASK (0xf << 0) + +/* PERF_CNT_SEL */ +#define OMAP44XX_REG_MCONNID2_SHIFT 24 +#define OMAP44XX_REG_MCONNID2_MASK (0xff << 24) +#define OMAP44XX_REG_REGION_SEL2_SHIFT 16 +#define OMAP44XX_REG_REGION_SEL2_MASK (0x3 << 16) +#define OMAP44XX_REG_MCONNID1_SHIFT 8 +#define OMAP44XX_REG_MCONNID1_MASK (0xff << 8) +#define OMAP44XX_REG_REGION_SEL1_SHIFT 0 +#define OMAP44XX_REG_REGION_SEL1_MASK (0x3 << 0) + +/* PERF_CNT_TIM */ +#define OMAP44XX_REG_TOTAL_TIME_SHIFT 0 +#define OMAP44XX_REG_TOTAL_TIME_MASK (0xffffffff << 0) + +/* READ_IDLE_CTRL */ +#define OMAP44XX_REG_READ_IDLE_LEN_SHIFT 16 +#define OMAP44XX_REG_READ_IDLE_LEN_MASK (0xf << 16) +#define OMAP44XX_REG_READ_IDLE_INTERVAL_SHIFT 0 +#define OMAP44XX_REG_READ_IDLE_INTERVAL_MASK (0x1ff << 0) + +/* READ_IDLE_CTRL_SHDW */ +#define OMAP44XX_REG_READ_IDLE_LEN_SHDW_SHIFT 16 +#define OMAP44XX_REG_READ_IDLE_LEN_SHDW_MASK (0xf << 16) +#define OMAP44XX_REG_READ_IDLE_INTERVAL_SHDW_SHIFT 0 +#define OMAP44XX_REG_READ_IDLE_INTERVAL_SHDW_MASK (0x1ff << 0) + +/* IRQ_EOI */ +#define OMAP44XX_REG_EOI_SHIFT 0 +#define OMAP44XX_REG_EOI_MASK (1 << 0) + +/* IRQSTATUS_RAW_SYS */ +#define OMAP44XX_REG_DNV_SYS_SHIFT 2 +#define OMAP44XX_REG_DNV_SYS_MASK (1 << 2) +#define OMAP44XX_REG_TA_SYS_SHIFT 1 +#define OMAP44XX_REG_TA_SYS_MASK (1 << 1) +#define OMAP44XX_REG_ERR_SYS_SHIFT 0 +#define OMAP44XX_REG_ERR_SYS_MASK (1 << 0) + +/* IRQSTATUS_RAW_LL */ +#define OMAP44XX_REG_DNV_LL_SHIFT 2 +#define OMAP44XX_REG_DNV_LL_MASK (1 << 2) +#define OMAP44XX_REG_TA_LL_SHIFT 1 +#define OMAP44XX_REG_TA_LL_MASK (1 << 1) +#define OMAP44XX_REG_ERR_LL_SHIFT 0 +#define OMAP44XX_REG_ERR_LL_MASK (1 << 0) + +/* IRQSTATUS_SYS */ + +/* IRQSTATUS_LL */ + +/* IRQENABLE_SET_SYS */ +#define OMAP44XX_REG_EN_DNV_SYS_SHIFT 2 +#define OMAP44XX_REG_EN_DNV_SYS_MASK (1 << 2) +#define OMAP44XX_REG_EN_TA_SYS_SHIFT 1 +#define OMAP44XX_REG_EN_TA_SYS_MASK (1 << 1) +#define OMAP44XX_REG_EN_ERR_SYS_SHIFT 0 +#define OMAP44XX_REG_EN_ERR_SYS_MASK (1 << 0) + +/* IRQENABLE_SET_LL */ +#define OMAP44XX_REG_EN_DNV_LL_SHIFT 2 +#define OMAP44XX_REG_EN_DNV_LL_MASK (1 << 2) +#define OMAP44XX_REG_EN_TA_LL_SHIFT 1 +#define OMAP44XX_REG_EN_TA_LL_MASK (1 << 1) +#define OMAP44XX_REG_EN_ERR_LL_SHIFT 0 +#define OMAP44XX_REG_EN_ERR_LL_MASK (1 << 0) + +/* IRQENABLE_CLR_SYS */ + +/* IRQENABLE_CLR_LL */ + +/* ZQ_CONFIG */ +#define OMAP44XX_REG_ZQ_CS1EN_SHIFT 31 +#define OMAP44XX_REG_ZQ_CS1EN_MASK (1 << 31) +#define OMAP44XX_REG_ZQ_CS0EN_SHIFT 30 +#define OMAP44XX_REG_ZQ_CS0EN_MASK (1 << 30) +#define OMAP44XX_REG_ZQ_DUALCALEN_SHIFT 29 +#define OMAP44XX_REG_ZQ_DUALCALEN_MASK (1 << 29) +#define OMAP44XX_REG_ZQ_SFEXITEN_SHIFT 28 +#define OMAP44XX_REG_ZQ_SFEXITEN_MASK (1 << 28) +#define OMAP44XX_REG_ZQ_ZQINIT_MULT_SHIFT 18 +#define OMAP44XX_REG_ZQ_ZQINIT_MULT_MASK (0x3 << 18) +#define OMAP44XX_REG_ZQ_ZQCL_MULT_SHIFT 16 +#define OMAP44XX_REG_ZQ_ZQCL_MULT_MASK (0x3 << 16) +#define OMAP44XX_REG_ZQ_REFINTERVAL_SHIFT 0 +#define OMAP44XX_REG_ZQ_REFINTERVAL_MASK (0xffff << 0) + +/* TEMP_ALERT_CONFIG */ +#define OMAP44XX_REG_TA_CS1EN_SHIFT 31 +#define OMAP44XX_REG_TA_CS1EN_MASK (1 << 31) +#define OMAP44XX_REG_TA_CS0EN_SHIFT 30 +#define OMAP44XX_REG_TA_CS0EN_MASK (1 << 30) +#define OMAP44XX_REG_TA_SFEXITEN_SHIFT 28 +#define OMAP44XX_REG_TA_SFEXITEN_MASK (1 << 28) +#define OMAP44XX_REG_TA_DEVWDT_SHIFT 26 +#define OMAP44XX_REG_TA_DEVWDT_MASK (0x3 << 26) +#define OMAP44XX_REG_TA_DEVCNT_SHIFT 24 +#define OMAP44XX_REG_TA_DEVCNT_MASK (0x3 << 24) +#define OMAP44XX_REG_TA_REFINTERVAL_SHIFT 0 +#define OMAP44XX_REG_TA_REFINTERVAL_MASK (0x3fffff << 0) + +/* OCP_ERR_LOG */ +#define OMAP44XX_REG_MADDRSPACE_SHIFT 14 +#define OMAP44XX_REG_MADDRSPACE_MASK (0x3 << 14) +#define OMAP44XX_REG_MBURSTSEQ_SHIFT 11 +#define OMAP44XX_REG_MBURSTSEQ_MASK (0x7 << 11) +#define OMAP44XX_REG_MCMD_SHIFT 8 +#define OMAP44XX_REG_MCMD_MASK (0x7 << 8) +#define OMAP44XX_REG_MCONNID_SHIFT 0 +#define OMAP44XX_REG_MCONNID_MASK (0xff << 0) + +/* DDR_PHY_CTRL_1 */ +#define OMAP44XX_REG_DDR_PHY_CTRL_1_SHIFT 4 +#define OMAP44XX_REG_DDR_PHY_CTRL_1_MASK (0xfffffff << 4) +#define OMAP44XX_REG_READ_LATENCY_SHIFT 0 +#define OMAP44XX_REG_READ_LATENCY_MASK (0xf << 0) +#define OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHIFT 4 +#define OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_MASK (0xFF << 4) +#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHIFT 12 +#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_MASK (0xFFFFF << 12) + +/* DDR_PHY_CTRL_1_SHDW */ +#define OMAP44XX_REG_DDR_PHY_CTRL_1_SHDW_SHIFT 4 +#define OMAP44XX_REG_DDR_PHY_CTRL_1_SHDW_MASK (0xfffffff << 4) +#define OMAP44XX_REG_READ_LATENCY_SHDW_SHIFT 0 +#define OMAP44XX_REG_READ_LATENCY_SHDW_MASK (0xf << 0) +#define OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHDW_SHIFT 4 +#define OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHDW_MASK (0xFF << 4) +#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHDW_SHIFT 12 +#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHDW_MASK (0xFFFFF << 12) + +/* DDR_PHY_CTRL_2 */ +#define OMAP44XX_REG_DDR_PHY_CTRL_2_SHIFT 0 +#define OMAP44XX_REG_DDR_PHY_CTRL_2_MASK (0xffffffff << 0) +#endif diff --git a/arch/arm/mach-omap2/include/mach/emif.h b/arch/arm/mach-omap2/include/mach/emif.h new file mode 100644 index 0000000..8a3ea34 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/emif.h @@ -0,0 +1,268 @@ +/* + * OMAP44xx EMIF header + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * Aneesh V <aneesh@ti.com> + * + * 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. + */ + +#ifndef _EMIF_H +#define _EMIF_H + +#include <mach/emif-44xx.h> +#include <mach/lpddr2-jedec.h> + +#define EMIF_NUM_INSTANCES 2 +#define EMIF1 0 +#define EMIF2 1 + +/* The maximum frequency at which the LPDDR2 interface can operate in Hz*/ +#define MAX_LPDDR2_FREQ 400000000 /* 400 MHz */ + +/* 19.2 MHz to be used for finding initialization values */ +#define EMIF_FREQ_19_2_MHZ 19200000 /* 19.2 MHz */ +/* + * The period of DDR clk is represented as numerator and denominator for + * better accuracy in integer based calculations. However, if the numerator + * and denominator are very huge there may be chances of overflow in + * calculations. So, as a trade-off keep denominator(and consequently + * numerator) within a limit sacrificing some accuracy - but not much + * If denominator and numerator are already small (such as at 400 MHz) + * no adjustment is needed + */ +#define EMIF_PERIOD_DEN_LIMIT 1000 +/* + * Maximum number of different frequencies supported by EMIF driver + * Determines the number of entries in the pointer array for register + * cache + */ +#define EMIF_MAX_NUM_FREQUENCIES 6 +/* + * Indices into the Addressing Table array. + * One entry each for all the different types of devices with different + * addressing schemes + */ +#define ADDR_TABLE_INDEX64M 0 +#define ADDR_TABLE_INDEX128M 1 +#define ADDR_TABLE_INDEX256M 2 +#define ADDR_TABLE_INDEX512M 3 +#define ADDR_TABLE_INDEX1GS4 4 +#define ADDR_TABLE_INDEX2GS4 5 +#define ADDR_TABLE_INDEX4G 6 +#define ADDR_TABLE_INDEX8G 7 +#define ADDR_TABLE_INDEX1GS2 8 +#define ADDR_TABLE_INDEX2GS2 9 +#define ADDR_TABLE_INDEXMAX 10 + +/* Number of Row bits */ +#define ROW_9 0 +#define ROW_10 1 +#define ROW_11 2 +#define ROW_12 3 +#define ROW_13 4 +#define ROW_14 5 +#define ROW_15 6 +#define ROW_16 7 + +/* Number of Column bits */ +#define COL_8 0 +#define COL_9 1 +#define COL_10 2 +#define COL_11 3 +#define COL_7 4 /*Not supported by OMAP included for completeness */ + +/* Number of Banks*/ +#define BANKS1 0 +#define BANKS2 1 +#define BANKS4 2 +#define BANKS8 3 + +/* Refresh rate in micro seconds x 10 */ +#define T_REFI_15_6 156 +#define T_REFI_7_8 78 +#define T_REFI_3_9 39 + +#define EBANK_CS1_DIS 0 +#define EBANK_CS1_EN 1 + +/* Read Latency at the base frequency - 19.2 MHz on bootup */ +#define RL_19_2_MHZ 3 +/* Interleaving policies at EMIF level- between banks and Chip Selects */ +#define EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING 0 +#define EMIF_INTERLEAVING_POLICY_NO_BANK_INTERLEAVING 3 + +/* + * Interleaving policy to be used + * Currently set to MAX interleaving for better performance + */ +#define EMIF_INTERLEAVING_POLICY EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING + +/* State of the core voltage: + * This is important for some parameters such as read idle control and + * ZQ calibration timings. Timings are much stricter when voltage ramp + * is happening compared to when the voltage is stable. + * We need to calculate two sets of values for these parameters and use + * them accordingly + */ +#define LPDDR2_VOLTAGE_STABLE 0 +#define LPDDR2_VOLTAGE_RAMPING 1 + +/* Length of the forced read idle period in terms of cycles */ +#define EMIF_REG_READ_IDLE_LEN_VAL 5 + +/* Interval between forced 'read idles' */ +/* To be used when voltage is changed for DPS/DVFS - 1us */ +#define READ_IDLE_INTERVAL_DVFS (1*1000) +/* + * To be used when voltage is not scaled except by Smart Reflex + * 50us - or maximum value will do + */ +#define READ_IDLE_INTERVAL_NORMAL (50*1000) + + +/* + * Unless voltage is changing due to DVFS one ZQCS command every 50ms should + * be enough. This shoule be enough also in the case when voltage is changing + * due to smart-reflex. + */ +#define EMIF_ZQCS_INTERVAL_NORMAL_IN_US (50*1000) +/* + * If voltage is changing due to DVFS ZQCS should be performed more + * often(every 50us) + */ +#define EMIF_ZQCS_INTERVAL_DVFS_IN_US 50 + +/* The interval between ZQCL commands as a multiple of ZQCS interval */ +#define REG_ZQ_ZQCL_MULT 4 +/* The interval between ZQINIT commands as a multiple of ZQCL interval */ +#define REG_ZQ_ZQINIT_MULT 3 +/* Enable ZQ Calibration on exiting Self-refresh */ +#define REG_ZQ_SFEXITEN_ENABLE 1 +/* + * ZQ Calibration simultaneously on both chip-selects: + * Needs one calibration resistor per CS + * None of the boards that we know of have this capability + * So disabled by default + */ +#define REG_ZQ_DUALCALEN_DISABLE 0 +/* + * Enable ZQ Calibration by default on CS0. If we are asked to program + * the EMIF there will be something connected to CS0 for sure + */ +#define REG_ZQ_CS0EN_ENABLE 1 + +/* EMIF_PWR_MGMT_CTRL register */ +/* Low power modes */ +#define LP_MODE_DISABLE 0 +#define LP_MODE_CLOCK_STOP 1 +#define LP_MODE_SELF_REFRESH 2 +#define LP_MODE_PWR_DN 3 + +/* REG_DPD_EN */ +#define DPD_DISABLE 0 +#define DPD_ENABLE 1 + +/* + * Value of bits 12:31 of DDR_PHY_CTRL_1 register: + * All these fields have magic values dependent on frequency and + * determined by PHY and DLL integration with EMIF. Setting the magic + * values suggested by hw team. + */ +#define EMIF_DDR_PHY_CTRL_1_BASE_VAL 0x049FF +#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ 0x41 +#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ 0x80 +#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS 0xFF + +/* +* MR1 value: +* Burst length : 8 +* Burst type : sequential +* Wrap : enabled +* nWR : 3(default). EMIF does not do pre-charge. +* : So nWR is don't care +*/ +#define MR1_VAL 0x23 + +/* MR10: ZQ calibration codes */ +#define MR10_ZQ_ZQCS 0x56 +#define MR10_ZQ_ZQCL 0xAB +#define MR10_ZQ_ZQINIT 0xFF +#define MR10_ZQ_ZQRESET 0xC3 + +/* TEMP_ALERT_CONFIG */ +#define TEMP_ALERT_POLL_INTERVAL_MS 360 /* for temp gradient - 5 C/s */ +#define TEMP_ALERT_CONFIG_DEVCT_1 0 +#define TEMP_ALERT_CONFIG_DEVWDT_32 2 + +/* MR16 value: refresh full array(no partial array self refresh) */ +#define MR16_VAL 0 + +#if defined(DEBUG) +#define emif_assert(c) BUG_ON(!(c)) +#else +#define emif_assert(c) ({ if (0) BUG_ON(!(c)); 0; }) +#endif + +/* Details of the devices connected to each chip-select of an EMIF instance */ +struct emif_device_details { + const struct lpddr2_device_info *cs0_device; + const struct lpddr2_device_info *cs1_device; +}; + +/* + * LPDDR2 interface clock frequency: + * Period (represented as numerator and denominator for better accuracy in + * calculations) should be <= the real value. Period is used for calculating + * all timings except refresh rate. + * freq_mhz_floor - freq in mhz truncated to the lower integer is used for + * calculating refresh rate + * freq_mhz_ceil - frequency in mhz rounded up is used for identifying the + * right speed bin and the corresponding timings table for the LPDDR2 device + */ +struct freq_info { + u16 period_num; + u16 period_den; + u16 freq_mhz_floor; + u16 freq_mhz_ceil; +}; + +/* + * Structure containing shadow of important registers in EMIF + * The calculation function fills in this structure to be later used for + * initialization and DVFS + */ +struct emif_regs { + u32 freq; + u8 RL_final; + u32 sdram_config_init; + u32 sdram_config_final; + u32 ref_ctrl; + u32 ref_ctrl_derated; + u32 sdram_tim1; + u32 sdram_tim1_derated; + u32 sdram_tim2; + u32 sdram_tim3; + u32 read_idle_ctrl_normal; + u32 read_idle_ctrl_volt_ramp; + u32 zq_config_normal; + u32 zq_config_volt_ramp; + u32 temp_alert_config; + u32 temp_alert_config_derated; + u32 emif_ddr_phy_ctlr_1_init; + u32 emif_ddr_phy_ctlr_1_final; +}; + +int omap_emif_setup_registers(u32 freq, + u32 volt_state); +void omap_emif_frequency_pre_notify(void); +void omap_emif_frequency_post_notify(void); +int omap_emif_setup_device_details( + const struct emif_device_details *emif1_devices, + const struct emif_device_details *emif2_devices); + +void emif_clear_irq(int emif_id); +#endif diff --git a/arch/arm/mach-omap2/include/mach/id.h b/arch/arm/mach-omap2/include/mach/id.h index 02ed3aa..096c02b 100644 --- a/arch/arm/mach-omap2/include/mach/id.h +++ b/arch/arm/mach-omap2/include/mach/id.h @@ -18,5 +18,6 @@ struct omap_die_id { }; void omap_get_die_id(struct omap_die_id *odi); +void omap_get_production_id(struct omap_die_id *odi); #endif diff --git a/arch/arm/mach-omap2/include/mach/lpddr2-elpida.h b/arch/arm/mach-omap2/include/mach/lpddr2-elpida.h new file mode 100644 index 0000000..b1accb8 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/lpddr2-elpida.h @@ -0,0 +1,23 @@ +/* + * ELPIDA LPDDR2 timings. + * + * Copyright (C) 2010 Texas Instruments + * + * Aneesh V <aneesh@ti.com> + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * 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. + */ + +#ifndef _LPDDR2_ELPIDA_H +#define _LPDDR2_ELPIDA_H + +extern const struct lpddr2_timings lpddr2_elpida_timings_200_mhz; +extern const struct lpddr2_timings lpddr2_elpida_timings_333_mhz; +extern const struct lpddr2_timings lpddr2_elpida_timings_400_mhz; +extern const struct lpddr2_min_tck lpddr2_elpida_min_tck; +extern struct lpddr2_device_info lpddr2_elpida_2G_S4_dev; + +#endif diff --git a/arch/arm/mach-omap2/include/mach/lpddr2-jedec.h b/arch/arm/mach-omap2/include/mach/lpddr2-jedec.h new file mode 100644 index 0000000..4545c29 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/lpddr2-jedec.h @@ -0,0 +1,149 @@ +/* + * LPDDR2 header based on JESD209-2 + * + * Copyright (C) 2010 Texas Instruments, Inc. + * + * Aneesh V <aneesh@ti.com> + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * 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. + */ + +#ifndef _LPDDR2_JDEC_H +#define _LPDDR2_JDEC_H + +#include <linux/types.h> + +/* + * Maximum number of entries we keep in our array of timing tables + * We need not keep all the speed bins supported by the device + * We need to keep timing tables for only the speed bins that we + * are interested in + */ +#define MAX_NUM_SPEEDBINS 4 + +/* LPDDR2 Densities */ +#define LPDDR2_DENSITY_64Mb 0 +#define LPDDR2_DENSITY_128Mb 1 +#define LPDDR2_DENSITY_256Mb 2 +#define LPDDR2_DENSITY_512Mb 3 +#define LPDDR2_DENSITY_1Gb 4 +#define LPDDR2_DENSITY_2Gb 5 +#define LPDDR2_DENSITY_4Gb 6 +#define LPDDR2_DENSITY_8Gb 7 +#define LPDDR2_DENSITY_16Gb 8 +#define LPDDR2_DENSITY_32Gb 9 + +/* LPDDR2 type */ +#define LPDDR2_TYPE_S4 0 +#define LPDDR2_TYPE_S2 1 +#define LPDDR2_TYPE_NVM 2 + +/* LPDDR2 IO width */ +#define LPDDR2_IO_WIDTH_32 0 +#define LPDDR2_IO_WIDTH_16 1 +#define LPDDR2_IO_WIDTH_8 2 + +/* Mode register numbers */ +#define LPDDR2_MR0 0 +#define LPDDR2_MR1 1 +#define LPDDR2_MR2 2 +#define LPDDR2_MR3 3 +#define LPDDR2_MR4 4 +#define LPDDR2_MR5 5 +#define LPDDR2_MR6 6 +#define LPDDR2_MR7 7 +#define LPDDR2_MR8 8 +#define LPDDR2_MR9 9 +#define LPDDR2_MR10 10 +#define LPDDR2_MR11 11 +#define LPDDR2_MR16 16 +#define LPDDR2_MR17 17 +#define LPDDR2_MR18 18 + +/* MR4 register fields */ +#define MR4_SDRAM_REF_RATE_SHIFT 0 +#define MR4_SDRAM_REF_RATE_MASK 7 +#define MR4_TUF_SHIFT 7 +#define MR4_TUF_MASK (1 << 7) + +/* MR4 SDRAM Refresh Rate field values */ +#define SDRAM_TEMP_NOMINAL 0x3 +#define SDRAM_TEMP_RESERVED_4 0x4 +#define SDRAM_TEMP_HIGH_DERATE_REFRESH 0x5 +#define SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS 0x6 +#define SDRAM_TEMP_VERY_HIGH_SHUTDOWN 0x7 + +struct lpddr2_addressing { + u8 num_banks; + u8 t_REFI_us_x10; + u8 row_sz[2]; /* One entry each for x32 and x16 */ + u8 col_sz[2]; /* One entry each for x32 and x16 */ +}; + +/* Structure for timings from the DDR datasheet */ +struct lpddr2_timings { + u32 max_freq; + u8 RL; + u8 tRPab; + u8 tRCD; + u8 tWR; + u8 tRASmin; + u8 tRRD; + u8 tWTRx2; + u8 tXSR; + u8 tXPx2; + u8 tRFCab; + u8 tRTPx2; + u8 tCKE; + u8 tCKESR; + u8 tZQCS; + u32 tZQCL; + u32 tZQINIT; + u8 tDQSCKMAXx2; + u8 tRASmax; + u8 tFAW; +}; + +/* + * Min tCK values for some of the parameters: + * If the calculated clock cycles for the respective parameter is + * less than the corresponding min tCK value, we need to set the min + * tCK value. This may happen at lower frequencies. + */ +struct lpddr2_min_tck { + u32 tRL; + u32 tRP_AB; + u32 tRCD; + u32 tWR; + u32 tRAS_MIN; + u32 tRRD; + u32 tWTR; + u32 tXP; + u32 tRTP; + u8 tCKE; + u32 tCKESR; + u32 tFAW; +}; + +struct lpddr2_device_info { + const struct lpddr2_timings *device_timings[MAX_NUM_SPEEDBINS]; + const struct lpddr2_min_tck *min_tck; + u8 type; + u8 density; + u8 io_width; + + /* Idle time in cycles to wait before putting the memory in self refresh */ + s32 emif_ddr_selfrefresh_cycles; +}; + +/* The following are exported for devices which use JDEC specifications */ +extern const struct lpddr2_addressing lpddr2_jedec_addressing_table[]; +extern const struct lpddr2_timings lpddr2_jedec_timings_400_mhz; +extern const struct lpddr2_timings lpddr2_jedec_timings_333_mhz; +extern const struct lpddr2_timings lpddr2_jedec_timings_200_mhz; +extern const struct lpddr2_min_tck lpddr2_jedec_min_tck; + +#endif diff --git a/arch/arm/mach-omap2/include/mach/omap-wakeupgen.h b/arch/arm/mach-omap2/include/mach/omap-wakeupgen.h new file mode 100644 index 0000000..66f31c3 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/omap-wakeupgen.h @@ -0,0 +1,41 @@ +/* + * OMAP WakeupGen header file + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Written by Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * 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. + */ +#ifndef OMAP_ARCH_WAKEUPGEN_H +#define OMAP_ARCH_WAKEUPGEN_H + +#define OMAP_WKG_CONTROL_0 0x00 +#define OMAP_WKG_ENB_A_0 0x10 +#define OMAP_WKG_ENB_B_0 0x14 +#define OMAP_WKG_ENB_C_0 0x18 +#define OMAP_WKG_ENB_D_0 0x1c +#define OMAP_WKG_ENB_SECURE_A_0 0x20 +#define OMAP_WKG_ENB_SECURE_B_0 0x24 +#define OMAP_WKG_ENB_SECURE_C_0 0x28 +#define OMAP_WKG_ENB_SECURE_D_0 0x2c +#define OMAP_WKG_ENB_A_1 0x410 +#define OMAP_WKG_ENB_B_1 0x414 +#define OMAP_WKG_ENB_C_1 0x418 +#define OMAP_WKG_ENB_D_1 0x41c +#define OMAP_WKG_ENB_SECURE_A_1 0x420 +#define OMAP_WKG_ENB_SECURE_B_1 0x424 +#define OMAP_WKG_ENB_SECURE_C_1 0x428 +#define OMAP_WKG_ENB_SECURE_D_1 0x42c +#define OMAP_AUX_CORE_BOOT_0 0x800 +#define OMAP_AUX_CORE_BOOT_1 0x804 +#define OMAP_PTMSYNCREQ_MASK 0xc00 +#define OMAP_PTMSYNCREQ_EN 0xc04 +#define OMAP_TIMESTAMPCYCLELO 0xc08 +#define OMAP_TIMESTAMPCYCLEHI 0xc0c + +extern int __init omap_wakeupgen_init(void); +extern void omap_wakeupgen_irqmask_all(unsigned int cpu, unsigned int set); +extern void omap_wakeupgen_save(void); +#endif diff --git a/arch/arm/mach-omap2/include/mach/omap4-common.h b/arch/arm/mach-omap2/include/mach/omap4-common.h index e4bd87619..f37cf4e 100644 --- a/arch/arm/mach-omap2/include/mach/omap4-common.h +++ b/arch/arm/mach-omap2/include/mach/omap4-common.h @@ -13,25 +13,84 @@ #ifndef OMAP_ARCH_OMAP4_COMMON_H #define OMAP_ARCH_OMAP4_COMMON_H +#include <asm/proc-fns.h> /* - * wfi used in low power code. Directly opcode is used instead - * of instruction to avoid mulit-omap build break + * Secure low power context save/restore API index */ -#ifdef CONFIG_THUMB2_KERNEL -#define do_wfi() __asm__ __volatile__ ("wfi" : : : "memory") -#else -#define do_wfi() \ - __asm__ __volatile__ (".word 0xe320f003" : : : "memory") -#endif +#define HAL_SAVESECURERAM_INDEX 0x1a +#define HAL_SAVEHW_INDEX 0x1b +#define HAL_SAVEALL_INDEX 0x1c +#define HAL_SAVEGIC_INDEX 0x1d + +/* + * Secure HAL, PPA services available + */ +#define PPA_SERVICE_0 0x21 +#define PPA_SERVICE_PL310_POR 0x23 +#define PPA_SERVICE_DEFAULT_POR_NS_SMP 0x25 +/* + * Secure HAL API flags + */ +#define FLAG_START_CRITICAL 0x4 +#define FLAG_IRQFIQ_MASK 0x3 +#define FLAG_IRQ_ENABLE 0x2 +#define FLAG_FIQ_ENABLE 0x1 +#define NO_FLAG 0x0 + +/* + * SAR restore phase USB HOST static port + * configuration + */ +#define OMAP4_USBHOST_CLKSEL_UTMI_P2_INT_P1_INT 0x0 +#define OMAP4_USBHOST_CLKSEL_UTMI_P2_INT_P1_EXT 0x1 +#define OMAP4_USBHOST_CLKSEL_UTMI_P2_EXT_P1_INT 0x2 +#define OMAP4_USBHOST_CLKSEL_UTMI_P2_EXT_P1_EXT 0x3 + +#ifndef __ASSEMBLER__ #ifdef CONFIG_CACHE_L2X0 -extern void __iomem *l2cache_base; +extern void __iomem *omap4_get_l2cache_base(void); #endif -extern void __iomem *gic_dist_base_addr; +#ifdef CONFIG_SMP +extern void __iomem *omap4_get_scu_base(void); +#else +static inline void __iomem *omap4_get_scu_base(void) +{ + return NULL; +} +#endif +extern void __iomem *omap4_get_gic_dist_base(void); +extern void __iomem *omap4_get_gic_cpu_base(void); +extern void __iomem *omap4_get_sar_ram_base(void); +extern void *omap_get_dram_barrier_base(void); +extern dma_addr_t omap4_secure_ram_phys; extern void __init gic_init_irq(void); +extern void gic_cpu_enable(void); +extern void gic_cpu_disable(void); +extern void gic_dist_enable(void); +extern void gic_dist_disable(void); +extern u32 gic_cpu_read(u32 reg); extern void omap_smc1(u32 fn, u32 arg); +extern void omap_bus_sync(void); +extern void omap_do_wfi(void); + +extern bool gic_dist_disabled(void); +extern void gic_timer_retrigger(void); + +/* + * Read MPIDR: Multiprocessor affinity register + */ +static inline unsigned int hard_smp_processor_id(void) +{ + unsigned int cpunum; + + asm volatile ( + "mrc p15, 0, %0, c0, c0, 5\n" + : "=r" (cpunum)); + return cpunum &= 0x0f; +} #ifdef CONFIG_SMP /* Needed for secondary core boot */ @@ -39,5 +98,65 @@ extern void omap_secondary_startup(void); extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask); extern void omap_auxcoreboot_addr(u32 cpu_addr); extern u32 omap_read_auxcoreboot0(void); + +#ifdef CONFIG_PM +extern int omap4_mpuss_init(void); +extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); +extern void omap4_cpu_suspend(unsigned int cpu, unsigned int save_state); +extern void omap4_cpu_resume(void); +extern u32 omap_smc2(u32 id, u32 falg, u32 pargs); +extern u32 omap4_secure_dispatcher(u32 idx, u32 flag, u32 nargs, + u32 arg1, u32 arg2, u32 arg3, u32 arg4); +#else +static inline int omap4_enter_lowpower(unsigned int cpu, + unsigned int power_state) +{ + cpu_do_idle(); + return 0; +} + +static inline int omap4_mpuss_init(void) +{ + return 0; +} + +static inline void omap4_cpu_suspend(unsigned int cpu, unsigned int save_state) +{ +} + +static inline void omap4_cpu_resume(void) +{ +} + +static inline u32 omap_smc2(u32 id, u32 falg, u32 pargs) +{ + return 0; +} +static inline u32 omap4_secure_dispatcher(u32 idx, u32 flag, u32 nargs, + u32 arg1, u32 arg2, u32 arg3, u32 arg4) +{ + return 0; +} +#endif /* CONFIG_PM */ +#endif /* CONFIG_SMP */ + +extern int omap4_prcm_freq_update(void); + +#ifdef CONFIG_PM +extern int omap4_sar_save(void); +extern void omap4_sar_overwrite(void); +extern void omap4_sar_usbhost_init(u32 fck_source); +#else +void omap4_sar_save(void) +{ +} +void omap4_sar_overwrite(void) +{ +} +void omap4_sar_usbhost_init(u32 fck_source) +{ +} #endif -#endif + +#endif /* __ASSEMBLER__ */ +#endif /* OMAP_ARCH_OMAP4_COMMON_H */ diff --git a/arch/arm/mach-omap2/include/mach/omap_fiq_debugger.h b/arch/arm/mach-omap2/include/mach/omap_fiq_debugger.h new file mode 100644 index 0000000..4378a77 --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/omap_fiq_debugger.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MACH_OMAP_FIQ_DEBUGGER_H +#define __MACH_OMAP_FIQ_DEBUGGER_H + +#ifdef CONFIG_OMAP_FIQ_DEBUGGER +int __init omap_serial_debug_init(int id, bool is_fiq, bool is_high_prio_irq, + struct omap_device_pad *pads, int num_pads); +u32 omap_debug_uart_resume_idle(void); + +#else +static inline int __init omap_serial_debug_init(int id, bool is_fiq, bool is_high_prio_irq, + struct omap_device_pad *pads, int num_pads) +{ + return 0; +} + +static inline u32 omap_debug_uart_resume_idle(void) +{ + return 0; +} +#endif + +#endif diff --git a/arch/arm/mach-omap2/include/mach/tiler.h b/arch/arm/mach-omap2/include/mach/tiler.h new file mode 100644 index 0000000..0fdb6eb --- /dev/null +++ b/arch/arm/mach-omap2/include/mach/tiler.h @@ -0,0 +1,513 @@ +/* + * tiler.h + * + * TILER driver support functions for TI TILER hardware block. + * + * Authors: Lajos Molnar <molnar@ti.com> + * David Sin <davidsin@ti.com> + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TILER_H +#define TILER_H + +#include <linux/mm.h> + +/* + * ----------------------------- API Definitions ----------------------------- + */ + +/* return true if physical address is in the tiler container */ +bool is_tiler_addr(u32 phys); + +enum tiler_fmt { + TILFMT_MIN = -2, + TILFMT_INVALID = -2, + TILFMT_NONE = -1, + TILFMT_8BIT = 0, + TILFMT_16BIT = 1, + TILFMT_32BIT = 2, + TILFMT_PAGE = 3, + TILFMT_MAX = 3, + TILFMT_8AND16 = 4, /* used to mark NV12 reserve block */ +}; + +/* tiler block info */ +struct tiler_block_t { + u32 phys; /* system space (L3) tiler addr */ + u32 width; /* width */ + u32 height; /* height */ + u32 key; /* secret key */ + u32 id; /* unique block ID */ +}; + +/* tiler (image/video frame) view */ +struct tiler_view_t { + u32 tsptr; /* tiler space addr */ + u32 width; /* width */ + u32 height; /* height */ + u32 bpp; /* bytes per pixel */ + s32 h_inc; /* horizontal increment */ + s32 v_inc; /* vertical increment */ +}; + +/* get the tiler format for a physical address or TILFMT_INVALID */ +enum tiler_fmt tiler_fmt(u32 phys); + +/* get the modified (1 for page mode) bytes-per-pixel for a tiler block */ +u32 tiler_bpp(const struct tiler_block_t *b); + +/* get tiler block physical stride */ +u32 tiler_pstride(const struct tiler_block_t *b); + +/* get tiler block virtual stride */ +static inline u32 tiler_vstride(const struct tiler_block_t *b) +{ + return PAGE_ALIGN((b->phys & ~PAGE_MASK) + tiler_bpp(b) * b->width); +} + +/* returns the virtual size of the block (for mmap) */ +static inline u32 tiler_size(const struct tiler_block_t *b) +{ + return b->height * tiler_vstride(b); +} + +/* Event types */ +#define TILER_DEVICE_CLOSE 0 + +/** + * Registers a notifier block with TILER driver. + * + * @param nb notifier_block + * + * @return error status + */ +s32 tiler_reg_notifier(struct notifier_block *nb); + +/** + * Un-registers a notifier block with TILER driver. + * + * @param nb notifier_block + * + * @return error status + */ +s32 tiler_unreg_notifier(struct notifier_block *nb); + +/** + * Get the physical address for a given user va. + * + * @param usr user virtual address + * + * @return valid pa or 0 for error + */ +u32 tiler_virt2phys(u32 usr); + +/** + * Reserves a 1D or 2D TILER block area and memory for the + * current process with group ID 0. + * + * @param blk pointer to tiler block data. This must be set up ('phys' member + * must be 0) with the tiler block information. 'height' must be 1 + * for 1D block. + * @param fmt TILER block format + * + * @return error status + */ +s32 tiler_alloc(struct tiler_block_t *blk, enum tiler_fmt fmt); + +/** + * Reserves a 1D or 2D TILER block area and memory for a set process and group + * ID. + * + * @param blk pointer to tiler block data. This must be set up ('phys' member + * must be 0) with the tiler block information. 'height' must be 1 + * for 1D block. + * @param fmt TILER block format + * @param gid group ID + * @param pid process ID + * + * @return error status + */ +s32 tiler_allocx(struct tiler_block_t *blk, enum tiler_fmt fmt, + u32 gid, pid_t pid); + +/** + * Mmaps a portion of a tiler block to a virtual address. Use this method in + * your driver's mmap function to potentially combine multiple tiler blocks as + * one virtual buffer. + * + * @param blk pointer to tiler block data + * @param offs offset from where to map (must be page aligned) + * @param size size of area to map (must be page aligned) + * @param vma VMM memory area to map to + * @param voffs offset (from vm_start) in the VMM memory area to start + * mapping at + * + * @return error status + */ +s32 tiler_mmap_blk(struct tiler_block_t *blk, u32 offs, u32 size, + struct vm_area_struct *vma, u32 voffs); + +/** + * Ioremaps a portion of a tiler block. Use this method in your driver instead + * of ioremap to potentially combine multiple tiler blocks as one virtual + * buffer. + * + * @param blk pointer to tiler block data + * @param offs offset from where to map (must be page aligned) + * @param size size of area to map (must be page aligned) + * @param addr virtual address + * @param mtype ioremap memory type (e.g. MT_DEVICE) + * + * @return error status + */ +s32 tiler_ioremap_blk(struct tiler_block_t *blk, u32 offs, u32 size, u32 addr, + u32 mtype); + +/** + * Maps an existing buffer to a 1D or 2D TILER area for the + * current process with group ID 0. + * + * Currently, only 1D area mapping is supported. + * + * NOTE: alignment is always PAGE_SIZE and offset is 0 as full pages are mapped + * into tiler container. + * + * @param blk pointer to tiler block data. This must be set up + * ('phys' member must be 0) with the tiler block + * information. 'height' must be 1 for 1D block. + * @param fmt TILER format + * @param usr_addr user space address of existing buffer. + * + * @return error status + */ +s32 tiler_map(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 usr_addr); + +/** + * Maps an existing buffer to a 1D or 2D TILER area for a set process and group + * ID. + * + * Currently, only 1D area mapping is supported. + * + * NOTE: alignment is always PAGE_SIZE and offset is 0 as full pages are mapped + * into tiler container. + * + * @param blk pointer to tiler block data. This must be set up + * ('phys' member must be 0) with the tiler block + * information. 'height' must be 1 for 1D block. + * @param fmt TILER format + * @param gid group ID + * @param pid process ID + * @param usr_addr user space address of existing buffer. + * + * @return error status + */ +s32 tiler_mapx(struct tiler_block_t *blk, enum tiler_fmt fmt, + u32 gid, pid_t pid, u32 usr_addr); + +/** + * Frees TILER memory. Since there may be multiple references for the same area + * if duplicated by tiler_dup, the area is only actually freed if all references + * have been freed. + * + * @param blk pointer to a tiler block data as filled by tiler_alloc, + * tiler_map or tiler_dup. 'phys' and 'id' members will be set to + * 0 on success. + */ +void tiler_free(struct tiler_block_t *blk); + +/** + * Reserves tiler area for n identical blocks for the current process. Use this + * method to get optimal placement of multiple identical tiler blocks; however, + * it may not reserve area if tiler_alloc is equally efficient. + * + * @param n number of identical set of blocks + * @param fmt TILER format + * @param width block width + * @param height block height (must be 1 for 1D) + */ +void tiler_reserve(u32 n, enum tiler_fmt fmt, u32 width, u32 height); + +/** + * Reserves tiler area for n identical blocks. Use this method to get optimal + * placement of multiple identical tiler blocks; however, it may not reserve + * area if tiler_alloc is equally efficient. + * + * @param n number of identical set of blocks + * @param fmt TILER bit mode + * @param width block width + * @param height block height (must be 1 for 1D) + * @param gid group ID + * @param pid process ID + */ +void tiler_reservex(u32 n, enum tiler_fmt fmt, u32 width, u32 height, + u32 gid, pid_t pid); + +/** + * Reserves tiler area for n identical NV12 blocks for the current process. Use + * this method to get optimal placement of multiple identical NV12 tiler blocks; + * however, it may not reserve area if tiler_alloc is equally efficient. + * + * @param n number of identical set of blocks + * @param width block width (Y) + * @param height block height (Y) + */ +void tiler_reserve_nv12(u32 n, u32 width, u32 height); + +/** + * Reserves tiler area for n identical NV12 blocks. Use this method to get + * optimal placement of multiple identical NV12 tiler blocks; however, it may + * not reserve area if tiler_alloc is equally efficient. + * + * @param n number of identical set of blocks + * @param width block width (Y) + * @param height block height (Y) + * @param gid group ID + * @param pid process ID + */ +void tiler_reservex_nv12(u32 n, u32 width, u32 height, u32 gid, pid_t pid); + +/** + * Create a view based on a tiler address and width and height + * + * This method should only be used as a last resort, e.g. if tilview object + * cannot be passed because of incoherence with other view 2D objects that must + * be supported. + * + * @param view Pointer to a view where the information will be stored + * @param ssptr MUST BE a tiler address + * @param width view width + * @param height view height + */ +void tilview_create(struct tiler_view_t *view, u32 phys, u32 width, u32 height); + +/** + * Obtains the view information for a tiler block + * + * @param view Pointer to a view where the information will be stored + * @param blk Pointer to an existing allocated tiler block + */ +void tilview_get(struct tiler_view_t *view, struct tiler_block_t *blk); + +/** + * Crops a tiler view to a rectangular portion. Crop area must be fully within + * the orginal tiler view: 0 <= left <= left + width <= view->width, also: + * 0 <= top <= top + height <= view->height. + * + * @param view Pointer to tiler view to be cropped + * @param left x of top-left corner + * @param top y of top-left corner + * @param width crop width + * @param height crop height + * + * @return error status. The view will be reduced to the crop region if the + * crop region is correct. Otherwise, no modifications are made. + */ +s32 tilview_crop(struct tiler_view_t *view, u32 left, u32 top, u32 width, + u32 height); + +/** + * Rotates a tiler view clockwise by a specified degree. + * + * @param view Pointer to tiler view to be cropped + * @param rotate Degree of rotation (clockwise). Must be a multiple of + * 90. + * @return error status. View is not modified on error; otherwise, it is + * updated in place. + */ +s32 tilview_rotate(struct tiler_view_t *view, s32 rotation); + +/** + * Mirrors a tiler view horizontally and/or vertically. + * + * @param view Pointer to tiler view to be cropped + * @param flip_x Mirror horizontally (left-to-right) + * @param flip_y Mirror vertically (top-to-bottom) + * + * @return error status. View is not modified on error; otherwise, it is + * updated in place. + */ +s32 tilview_flip(struct tiler_view_t *view, bool flip_x, bool flip_y); + +/* + * -------------------- TILER hooks for ION/HWC migration -------------------- + */ + +/* type of tiler memory */ +enum tiler_memtype { + TILER_MEM_ALLOCED, /* tiler allocated the memory */ + TILER_MEM_GOT_PAGES, /* tiler used get_user_pages */ + TILER_MEM_USING, /* tiler is using the pages */ +}; + +/* physical pages to pin - mem must be kmalloced */ +struct tiler_pa_info { + u32 num_pg; /* number of pages in page-list */ + u32 *mem; /* list of phys page addresses */ + enum tiler_memtype memtype; /* how we got physical pages */ +}; + +typedef struct mem_info *tiler_blk_handle; + +/** + * Allocate a 1D area of container space in the Tiler + * + * @param pa ptr to tiler_pa_info structure + * + * @return handle Handle to tiler block information. NULL on error. + * + * NOTE: this will take ownership pa->mem (will free it) + * + */ +tiler_blk_handle tiler_map_1d_block(struct tiler_pa_info *pa); + +/** + * Allocate an area of container space in the Tiler + * + * @param fmt Tiler bpp mode + * @param width Width in pixels + * @param height Height in pixels + * @param ssptr Value of tiler physical address of allocation + * @param virt_array Array of physical address for the start of each virtual + page + * + * @return handle Handle to tiler block information. NULL on error. + * + * NOTE: For 1D allocations, specify the full size in the width field, and + * specify a height of 1. + */ +tiler_blk_handle tiler_alloc_block_area(enum tiler_fmt fmt, u32 width, + u32 height, u32 *ssptr, + u32 *virt_array); + +/** + * Free a reserved area in the Tiler + * + * @param handle Handle to tiler block information + * + */ +void tiler_free_block_area(tiler_blk_handle block); + +/** + * Pins a set of physical pages into the Tiler using the area defined in a + * handle + * + * @param handle Handle to tiler block information + * @param addr_array Array of addresses + * @param nents Number of addresses in array + * + * @return error status. + */ +s32 tiler_pin_block(tiler_blk_handle handle, u32 *addr_array, u32 nents); + +/** + * Unpins a set of physical pages from the Tiler + * + * @param handle Handle to tiler block information + * + */ +void tiler_unpin_block(tiler_blk_handle handle); + +/** + * Gives memory requirements for a given container allocation + * + * @param fmt Tiler bpp mode + * @param width Width in pixels + * @param height Height in pixels + * @param alloc_pages Number of pages required to back tiler container + * @param virt_pages Number of pages required to back the virtual address space + * + * @return 0 for success. Non zero for error + */ +s32 tiler_memsize(enum tiler_fmt fmt, u32 width, u32 height, u32 *alloc_pages, + u32 *virt_pages); + +/** + * Returns virtual stride of a tiler block + * + * @param handle Handle to tiler block allocation + * + * @return Size of virtual stride + */ +u32 tiler_block_vstride(tiler_blk_handle handle); + +struct tiler_pa_info *user_block_to_pa(u32 usr_addr, u32 num_pg); +void tiler_pa_free(struct tiler_pa_info *pa); + +/* + * ---------------------------- IOCTL Definitions ---------------------------- + */ + +/* ioctls */ +#define TILIOC_GBLK _IOWR('z', 100, struct tiler_block_info) +#define TILIOC_FBLK _IOW('z', 101, struct tiler_block_info) +#define TILIOC_GSSP _IOWR('z', 102, u32) +#define TILIOC_MBLK _IOWR('z', 103, struct tiler_block_info) +#define TILIOC_UMBLK _IOW('z', 104, struct tiler_block_info) +#define TILIOC_QBUF _IOWR('z', 105, struct tiler_buf_info) +#define TILIOC_RBUF _IOWR('z', 106, struct tiler_buf_info) +#define TILIOC_URBUF _IOWR('z', 107, struct tiler_buf_info) +#define TILIOC_QBLK _IOWR('z', 108, struct tiler_block_info) +#define TILIOC_PRBLK _IOW('z', 109, struct tiler_block_info) +#define TILIOC_URBLK _IOW('z', 110, u32) + +struct area { + u16 width; + u16 height; +}; + +/* userspace tiler block info */ +struct tiler_block_info { + enum tiler_fmt fmt; + union { + struct area area; + u32 len; + } dim; + u32 stride; /* stride is not maintained for 1D blocks */ + void *ptr; /* userspace address for mapping existing buffer */ + u32 id; + u32 key; + u32 group_id; + u32 ssptr; /* physical address, may not exposed by default */ +}; + +#define TILER_MAX_NUM_BLOCKS 16 + +/* userspace tiler buffer info */ +struct tiler_buf_info { + u32 num_blocks; + struct tiler_block_info blocks[TILER_MAX_NUM_BLOCKS]; + u32 offset; + u32 length; /* also used as number of buffers for reservation */ +}; + +#endif diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 441e79d..b5c8e80 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -38,6 +38,7 @@ #include "io.h" #include <plat/omap-pm.h> +#include "voltage.h" #include "powerdomain.h" #include "clockdomain.h" @@ -355,18 +356,22 @@ void __init omap2_init_common_infrastructure(void) u8 postsetup_state; if (cpu_is_omap242x()) { + omap2xxx_voltagedomains_init(); omap2xxx_powerdomains_init(); omap2xxx_clockdomains_init(); omap2420_hwmod_init(); } else if (cpu_is_omap243x()) { + omap2xxx_voltagedomains_init(); omap2xxx_powerdomains_init(); omap2xxx_clockdomains_init(); omap2430_hwmod_init(); } else if (cpu_is_omap34xx()) { + omap3xxx_voltagedomains_init(); omap3xxx_powerdomains_init(); omap3xxx_clockdomains_init(); omap3xxx_hwmod_init(); } else if (cpu_is_omap44xx()) { + omap44xx_voltagedomains_init(); omap44xx_powerdomains_init(); omap44xx_clockdomains_init(); omap44xx_hwmod_init(); diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c index adb083e..f42a4a3 100644 --- a/arch/arm/mach-omap2/iommu2.c +++ b/arch/arm/mach-omap2/iommu2.c @@ -19,6 +19,7 @@ #include <linux/stringify.h> #include <plat/iommu.h> +#include <plat/omap_device.h> /* * omap2 architecture specific register bit definitions @@ -84,18 +85,25 @@ static void __iommu_set_twl(struct iommu *obj, bool on) iommu_write_reg(obj, l, MMU_CNTL); } - static int omap2_iommu_enable(struct iommu *obj) { u32 l, pa; unsigned long timeout; + int ret = 0; + + if (!obj->secure_mode) { + if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd, SZ_16K)) + return -EINVAL; - if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd, SZ_16K)) - return -EINVAL; + pa = virt_to_phys(obj->iopgd); + if (!IS_ALIGNED(pa, SZ_16K)) + return -EINVAL; + } else + pa = (u32)obj->secure_ttb; - pa = virt_to_phys(obj->iopgd); - if (!IS_ALIGNED(pa, SZ_16K)) - return -EINVAL; + ret = omap_device_enable(obj->pdev); + if (ret) + return ret; iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG); @@ -124,11 +132,16 @@ static int omap2_iommu_enable(struct iommu *obj) __iommu_set_twl(obj, true); + if (cpu_is_omap44xx()) + iommu_write_reg(obj, 0x1, MMU_GP_REG); + return 0; } static void omap2_iommu_disable(struct iommu *obj) { + int ret = 0; + u32 l = iommu_read_reg(obj, MMU_CNTL); l &= ~MMU_CNTL_MASK; @@ -136,6 +149,8 @@ static void omap2_iommu_disable(struct iommu *obj) iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG); dev_dbg(obj->dev, "%s is shutting down\n", obj->name); + if (omap_device_shutdown(obj->pdev)) + dev_err(obj->dev, "%s err 0x%x\n", __func__, ret); } static void omap2_iommu_set_twl(struct iommu *obj, bool on) @@ -168,7 +183,6 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) errs |= OMAP_IOMMU_ERR_TBLWALK_FAULT; if (stat & MMU_IRQ_MULTIHITFAULT) errs |= OMAP_IOMMU_ERR_MULTIHIT_FAULT; - iommu_write_reg(obj, stat, MMU_IRQSTATUS); return errs; } @@ -225,7 +239,8 @@ static u32 omap2_get_pte_attr(struct iotlb_entry *e) attr = e->mixed << 5; attr |= e->endian; attr |= e->elsz >> 3; - attr <<= ((e->pgsz & MMU_CAM_PGSZ_4K) ? 0 : 6); + attr <<= (((e->pgsz == MMU_CAM_PGSZ_4K) || + (e->pgsz == MMU_CAM_PGSZ_64K)) ? 0 : 6); return attr; } diff --git a/arch/arm/mach-omap2/ldo.c b/arch/arm/mach-omap2/ldo.c new file mode 100644 index 0000000..13ee2a3 --- /dev/null +++ b/arch/arm/mach-omap2/ldo.c @@ -0,0 +1,333 @@ +/* + * OMAP3/4 LDO users core + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Mike Turquette <mturquette@ti.com> + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/init.h> + +#include <plat/cpu.h> +#include "voltage.h" +#include "ldo.h" + +/** + * _is_abb_enabled() - check if abb is enabled + * @voltdm: voltage domain to check for + * @abb: abb instance pointer + * + * Returns true if enabled, else returns false + */ +static inline bool _is_abb_enabled(struct voltagedomain *voltdm, + struct omap_ldo_abb_instance *abb) +{ + return (voltdm->read(abb->setup_reg) & abb->setup_bits->enable_mask) ? + true : false; +} + +/** + * _abb_set_availability() - sets the availability of the ABB LDO + * @voltdm: voltage domain for which we would like to set + * @abb: abb instance pointer + * @available: should I enable/disable the LDO? + * + * Depending on the request, it enables/disables the LDO if it was not + * in that state already. + */ +static inline void _abb_set_availability(struct voltagedomain *voltdm, + struct omap_ldo_abb_instance *abb, + bool available) +{ + if (_is_abb_enabled(voltdm, abb) == available) + return; + + voltdm->rmw(abb->setup_bits->enable_mask, + (available) ? abb->setup_bits->enable_mask : 0, + abb->setup_reg); +} + +/** + * _abb_wait_tranx() - wait for abb tranxdone event + * @voltdm: voltage domain we are operating on + * @abb: pointer to the abb instance + * + * Returns -ETIMEDOUT if the event is not set on time. + */ +static int _abb_wait_tranx(struct voltagedomain *voltdm, + struct omap_ldo_abb_instance *abb) +{ + int timeout; + int ret; + + timeout = 0; + while (timeout++ < abb->tranx_timeout) { + ret = abb->ops->check_txdone(abb->prm_irq_id); + if (ret) + break; + + udelay(1); + } + + if (timeout >= abb->tranx_timeout) { + pr_warning("%s:%s: ABB TRANXDONE waittimeout(timeout=%d)\n", + __func__, voltdm->name, timeout); + return -ETIMEDOUT; + } + return 0; +} + +/** + * _abb_clear_tranx() - clear abb tranxdone event + * @voltdm: voltage domain we are operating on + * @abb: pointer to the abb instance + * + * Returns -ETIMEDOUT if the event is not cleared on time. + */ +static int _abb_clear_tranx(struct voltagedomain *voltdm, + struct omap_ldo_abb_instance *abb) +{ + int timeout; + int ret; + + /* clear interrupt status */ + timeout = 0; + while (timeout++ < abb->tranx_timeout) { + abb->ops->clear_txdone(abb->prm_irq_id); + + ret = abb->ops->check_txdone(abb->prm_irq_id); + if (!ret) + break; + + udelay(1); + } + + if (timeout >= abb->tranx_timeout) { + pr_warning("%s:%s: ABB TRANXDONE timeout(timeout=%d)\n", + __func__, voltdm->name, timeout); + return -ETIMEDOUT; + } + return 0; +} + +/** + * _abb_set_abb() - helper to actually set ABB (NOMINAL/FAST) + * @voltdm: voltage domain we are operating on + * @abb_type: ABB type we want to set + */ +static int _abb_set_abb(struct voltagedomain *voltdm, int abb_type) +{ + struct omap_ldo_abb_instance *abb = voltdm->abb; + int ret; + + ret = _abb_clear_tranx(voltdm, abb); + if (ret) + return ret; + + /* program next state of ABB ldo */ + voltdm->rmw(abb->ctrl_bits->opp_sel_mask, + abb_type << __ffs(abb->ctrl_bits->opp_sel_mask), + abb->ctrl_reg); + + /* initiate ABB ldo change */ + voltdm->rmw(abb->ctrl_bits->opp_change_mask, + abb->ctrl_bits->opp_change_mask, abb->ctrl_reg); + + /* Wait for conversion completion */ + ret = _abb_wait_tranx(voltdm, abb); + WARN_ONCE(ret, "%s: voltdm %s ABB TRANXDONE was not set on time:%d\n", + __func__, voltdm->name, ret); + /* clear interrupt status */ + ret |= _abb_clear_tranx(voltdm, abb); + + return ret; +} + +/** + * _abb_scale() - wrapper which does the necessary things for pre and post scale + * @voltdm: voltage domain to operate on + * @target_volt: voltage we are going to + * @is_prescale: are we doing a prescale operation? + * + * NOTE: We expect caller ensures that a specific voltdm is modified + * sequentially. All locking is expected to be implemented by users + * of LDO functions + */ +static int _abb_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_vdata, bool is_prescale) +{ + int ret = 0; + int curr_abb, target_abb; + struct omap_ldo_abb_instance *abb; + + if (IS_ERR_OR_NULL(target_vdata)) { + pr_err("%s:%s: Invalid volt data tv=%p!\n", __func__, + voltdm->name, target_vdata); + return -EINVAL; + } + + abb = voltdm->abb; + if (IS_ERR_OR_NULL(abb)) { + WARN(1, "%s:%s: no abb structure!\n", __func__, voltdm->name); + return -EINVAL; + } + + curr_abb = abb->__cur_abb_type; + target_abb = target_vdata->abb_type; + + pr_debug("%s: %s: Enter: t_v=%ld scale=%d c_abb=%d t_abb=%d ret=%d\n", + __func__, voltdm->name, omap_get_nominal_voltage(target_vdata), + is_prescale, curr_abb, target_abb, ret); + + /* If we were'nt booting and there is no change, we get out */ + if (target_abb == curr_abb && voltdm->curr_volt) + goto out; + + /* Do we have an invalid ABB entry? scream for a fix! */ + if (curr_abb == OMAP_ABB_NONE || target_abb == OMAP_ABB_NONE) { + WARN(1, "%s:%s: INVALID abb entries? curr=%d target=%d\n", + __func__, voltdm->name, curr_abb, target_abb); + return -EINVAL; + } + + /* + * We set up ABB as follows: + * if we are scaling *to* a voltage which needs ABB, do it in post + * if we are scaling *from* a voltage which needs ABB, do it in pre + * So, if the conditions are in reverse, we just return happy + */ + if (is_prescale && (target_abb > curr_abb)) + goto out; + + if (!is_prescale && (target_abb < curr_abb)) + goto out; + + /* Time to set ABB now */ + ret = _abb_set_abb(voltdm, target_abb); + if (!ret) { + abb->__cur_abb_type = target_abb; + pr_debug("%s: %s: scaled - t_abb=%d!\n", __func__, + voltdm->name, target_abb); + } else { + pr_warning("%s: %s: failed scale: t_abb=%d (%d)!\n", __func__, + voltdm->name, target_abb, ret); + } + +out: + pr_debug("%s: %s:Exit: t_v=%ld scale=%d c_abb=%d t_abb=%d ret=%d\n", + __func__, voltdm->name, omap_get_nominal_voltage(target_vdata), + is_prescale, curr_abb, target_abb, ret); + return ret; + +} + +/** + * omap_ldo_abb_pre_scale() - Enable required ABB strategy before voltage scale + * @voltdm: voltage domain to operate on + * @target_volt: target voltage data we moved to. + */ +int omap_ldo_abb_pre_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_vdata) +{ + return _abb_scale(voltdm, target_vdata, true); +} + +/** + * omap_ldo_abb_pre_scale() - Enable required ABB strategy after voltage scale + * @voltdm: voltage domain operated on + * @target_volt: target voltage we are going to + */ +int omap_ldo_abb_post_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_vdata) +{ + return _abb_scale(voltdm, target_vdata, false); +} + +/** + * omap_ldo_abb_init() - initialize the ABB LDO for associated for this domain + * @voltdm: voltdm for which we need to initialize the ABB LDO + * + * Programs up the the configurations that dont change in the domain + * + * Return 0 if all goes fine, else returns appropriate error value + */ +void __init omap_ldo_abb_init(struct voltagedomain *voltdm) +{ + u32 sys_clk_rate; + u32 cycle_rate; + u32 settling_time; + u32 wait_count_val; + struct omap_ldo_abb_instance *abb; + + if (IS_ERR_OR_NULL(voltdm)) { + pr_err("%s: No voltdm?\n", __func__); + return; + } + if (!voltdm->read || !voltdm->write || !voltdm->rmw) { + pr_err("%s: No read/write/rmw API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + abb = voltdm->abb; + if (IS_ERR_OR_NULL(abb)) + return; + if (IS_ERR_OR_NULL(abb->ctrl_bits) || IS_ERR_OR_NULL(abb->setup_bits)) { + pr_err("%s: Corrupted ABB configuration on vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + /* + * SR2_WTCNT_VALUE must be programmed with the expected settling time + * for ABB ldo transition. This value depends on the cycle rate for + * the ABB IP (varies per OMAP family), and the system clock frequency + * (varies per board). The formula is: + * + * SR2_WTCNT_VALUE = SettlingTime / (CycleRate / SystemClkRate)) + * where SettlingTime is in micro-seconds and SystemClkRate is in MHz. + * + * To avoid dividing by zero multiply both CycleRate and SettlingTime + * by 10 such that the final result is the one we want. + */ + + /* Convert SYS_CLK rate to MHz & prevent divide by zero */ + sys_clk_rate = DIV_ROUND_CLOSEST(voltdm->sys_clk.rate, 1000000); + cycle_rate = abb->cycle_rate * 10; + settling_time = abb->settling_time * 10; + + /* Calculate cycle rate */ + cycle_rate = DIV_ROUND_CLOSEST(cycle_rate, sys_clk_rate); + + /* Calulate SR2_WTCNT_VALUE */ + wait_count_val = DIV_ROUND_CLOSEST(settling_time, cycle_rate); + + voltdm->rmw(abb->setup_bits->wait_count_mask, + wait_count_val << __ffs(abb->setup_bits->wait_count_mask), + abb->setup_reg); + + /* Allow Forward Body-Bias */ + voltdm->rmw(abb->setup_bits->active_fbb_mask, + abb->setup_bits->active_fbb_mask, abb->setup_reg); + + /* Enable ABB */ + _abb_set_availability(voltdm, abb, true); + + /* + * Beware of the bootloader! + * Initialize current abb type based on what we read off the reg. + * we cant trust the initial state based off boot voltage's volt_data + * even. Not all bootloaders are nice :( + */ + abb->__cur_abb_type = (voltdm->read(abb->ctrl_reg) & + abb->ctrl_bits->opp_sel_mask) >> + __ffs(abb->ctrl_bits->opp_sel_mask); + + return; +} diff --git a/arch/arm/mach-omap2/ldo.h b/arch/arm/mach-omap2/ldo.h new file mode 100644 index 0000000..44e66f4 --- /dev/null +++ b/arch/arm/mach-omap2/ldo.h @@ -0,0 +1,113 @@ +/* + * OMAP3/4 LDO structure and macro definitions + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Mike Turquette <mturquette@ti.com> + * Nishanth Menon + * + * 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. + */ + +#ifndef __ARCH_ARM_MACH_OMAP2_LDO_H +#define __ARCH_ARM_MACH_OMAP2_LDO_H + + +/** + * struct omap_ldo_abb_ops - ABB LDO status operation pointers + * @check_txdone: check if the transaction is done + * @clear_txdone: clear the transaction done event + */ +struct omap_ldo_abb_ops { + u32(*check_txdone) (u8 irq_id); + void (*clear_txdone) (u8 irq_id); +}; + +/* + * NOTE: OMAP3630 calls this the ctrl register, while + * OMAP4430, OMAP4460 is setup + */ +#define OMAP_LDO_ABB_SETUP_SR2_WTCNT_VALUE_MASK (0xFF << 8) +#define OMAP_LDO_ABB_SETUP_ACTIVE_FBB_SEL_MASK BIT(2) +#define OMAP_LDO_ABB_SETUP_SR2EN_MASK BIT(0) + +/** + * struct omap_ldo_abb_setup_bits - setup register bit defns + * @enable_mask: SR2EN field + * @active_fbb_mask: ACTIVE_FBB_SEL field + * @wait_count_mask: SR2_WTCNT_VALUE field + */ +struct omap_ldo_abb_setup_bits { + u32 enable_mask; + u32 active_fbb_mask; + /* RBB is not recommended to be used and hence not supported */ + u32 wait_count_mask; +}; + +/* + * NOTE: OMAP3630 calls this the setup register, while + * OMAP4430, OMAP4460 is ctrl + */ +#define OMAP_LDO_ABB_CTRL_SR2_IN_TRANSITION_MASK BIT(6) +#define OMAP_LDO_ABB_CTRL_SR2_STATUS_MASK (0x3 << 3) +#define OMAP_LDO_ABB_CTRL_OPP_CHANGE_MASK BIT(2) +#define OMAP_LDO_ABB_CTRL_OPP_SEL_MASK (0x3 << 0) + +/** + * struct omap_ldo_abb_ctrl_bits - ctrl register bit defns + * @in_tansition_mask: SR2_IN_TRANSITION field + * @status_mask: SR2_STATUS field + * @opp_change_mask: OPP_CHANGE field + * @opp_sel_mask: OPP_SEL field + */ +struct omap_ldo_abb_ctrl_bits { + u32 in_tansition_mask; + u32 status_mask; + u32 opp_change_mask; + u32 opp_sel_mask; +}; + +#define OMAP_ABB_TRANXDONE_TIMEOUT_US 50 + +/** + * struct omap_ldo_abb_instance - Describe an LDO instance + * @prm_irq_id: PRM irq id for relevant for this block + * @ctrl_reg: control reg offset + * @setup_reg: setup reg offset + * @ctrl_bits: pointer to control register bitfield + * @setup_bits: pointer to setup register bitfield + * @settling_time: OMAP internal settling time(in uS) + * @cycle_rate: Cycle rate for the IP block + * @tranx_timeout: timeout count in uSec + * @ops: operations for ldo_abb + * @__cur_abb_type: private structure used by the driver, donot use. + */ +struct omap_ldo_abb_instance { + u8 prm_irq_id; + + u32 ctrl_reg; + u32 setup_reg; + struct omap_ldo_abb_ctrl_bits *ctrl_bits; + struct omap_ldo_abb_setup_bits *setup_bits; + + unsigned long settling_time; + unsigned long cycle_rate; + unsigned int tranx_timeout; + + struct omap_ldo_abb_ops *ops; + int __cur_abb_type; +}; + +extern struct omap_ldo_abb_instance omap3630_ldo_abb_mpu_instance; + +extern struct omap_ldo_abb_instance omap4_ldo_abb_mpu_instance; +extern struct omap_ldo_abb_instance omap4_ldo_abb_iva_instance; + +extern int omap_ldo_abb_pre_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_vdata); +extern int omap_ldo_abb_post_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_vdata); +extern void __init omap_ldo_abb_init(struct voltagedomain *voltdm); + +#endif /* __ARCH_ARM_MACH_OMAP2_LDO_H */ diff --git a/arch/arm/mach-omap2/ldo3xxx_data.c b/arch/arm/mach-omap2/ldo3xxx_data.c new file mode 100644 index 0000000..870a912 --- /dev/null +++ b/arch/arm/mach-omap2/ldo3xxx_data.c @@ -0,0 +1,49 @@ +/* + * OMAP3xxx LDO data + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Mike Turquette <mturquette@ti.com> + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "voltage.h" +#include "ldo.h" +#include "prm2xxx_3xxx.h" +#include "prm-regbits-34xx.h" + +static struct omap_ldo_abb_ops omap3630_ldo_abb_ops = { + .check_txdone = omap36xx_prm_abb_check_txdone, + .clear_txdone = omap36xx_prm_abb_clear_txdone, +}; + +/* WARNING: OMAP3630 as per TRM rev J, has the register names inverted */ + +static struct omap_ldo_abb_setup_bits omap3630_ldo_abb_setup_bits = { + .enable_mask = OMAP_LDO_ABB_SETUP_SR2EN_MASK, + .active_fbb_mask = OMAP_LDO_ABB_SETUP_ACTIVE_FBB_SEL_MASK, + .wait_count_mask = OMAP_LDO_ABB_SETUP_SR2_WTCNT_VALUE_MASK, +}; + +static struct omap_ldo_abb_ctrl_bits omap3630_ldo_abb_ctrl_bits = { + .in_tansition_mask = OMAP_LDO_ABB_CTRL_SR2_IN_TRANSITION_MASK, + .status_mask = OMAP_LDO_ABB_CTRL_SR2_STATUS_MASK, + .opp_change_mask = OMAP_LDO_ABB_CTRL_OPP_CHANGE_MASK, + .opp_sel_mask = OMAP_LDO_ABB_CTRL_OPP_SEL_MASK, +}; + +struct omap_ldo_abb_instance omap3630_ldo_abb_mpu_instance = { + .prm_irq_id = OMAP3_PRM_IRQ_VDD_MPU_ID, + .ctrl_reg = OMAP3_PRM_LDO_ABB_CTRL_OFFSET, + .setup_reg = OMAP3_PRM_LDO_ABB_SETUP_OFFSET, + .ctrl_bits = &omap3630_ldo_abb_ctrl_bits, + .setup_bits = &omap3630_ldo_abb_setup_bits, + .ops = &omap3630_ldo_abb_ops, + + .settling_time = 30, + .cycle_rate = 8, + .tranx_timeout = OMAP_ABB_TRANXDONE_TIMEOUT_US, +}; diff --git a/arch/arm/mach-omap2/ldo4xxx_data.c b/arch/arm/mach-omap2/ldo4xxx_data.c new file mode 100644 index 0000000..161e957 --- /dev/null +++ b/arch/arm/mach-omap2/ldo4xxx_data.c @@ -0,0 +1,60 @@ +/* + * OMAP4xxx LDO data + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Mike Turquette <mturquette@ti.com> + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "voltage.h" +#include "ldo.h" +#include "prm44xx.h" +#include "prm-regbits-44xx.h" + +static struct omap_ldo_abb_ops omap4_ldo_abb_ops = { + .check_txdone = omap4_prm_abb_check_txdone, + .clear_txdone = omap4_prm_abb_clear_txdone, +}; + +static struct omap_ldo_abb_setup_bits omap4_ldo_abb_setup_bits = { + .enable_mask = OMAP_LDO_ABB_SETUP_SR2EN_MASK, + .active_fbb_mask = OMAP_LDO_ABB_SETUP_ACTIVE_FBB_SEL_MASK, + .wait_count_mask = OMAP_LDO_ABB_SETUP_SR2_WTCNT_VALUE_MASK, +}; + +static struct omap_ldo_abb_ctrl_bits omap4_ldo_abb_ctrl_bits = { + .in_tansition_mask = OMAP_LDO_ABB_CTRL_SR2_IN_TRANSITION_MASK, + .status_mask = OMAP_LDO_ABB_CTRL_SR2_STATUS_MASK, + .opp_change_mask = OMAP_LDO_ABB_CTRL_OPP_CHANGE_MASK, + .opp_sel_mask = OMAP_LDO_ABB_CTRL_OPP_SEL_MASK, +}; + +struct omap_ldo_abb_instance omap4_ldo_abb_mpu_instance = { + .prm_irq_id = OMAP4_PRM_IRQ_VDD_MPU_ID, + .ctrl_reg = OMAP4_PRM_LDO_ABB_MPU_CTRL_OFFSET, + .setup_reg = OMAP4_PRM_LDO_ABB_MPU_SETUP_OFFSET, + .ctrl_bits = &omap4_ldo_abb_ctrl_bits, + .setup_bits = &omap4_ldo_abb_setup_bits, + .ops = &omap4_ldo_abb_ops, + + .settling_time = 50, + .cycle_rate = 16, + .tranx_timeout = OMAP_ABB_TRANXDONE_TIMEOUT_US, +}; + +struct omap_ldo_abb_instance omap4_ldo_abb_iva_instance = { + .prm_irq_id = OMAP4_PRM_IRQ_VDD_IVA_ID, + .ctrl_reg = OMAP4_PRM_LDO_ABB_IVA_CTRL_OFFSET, + .setup_reg = OMAP4_PRM_LDO_ABB_IVA_SETUP_OFFSET, + .ctrl_bits = &omap4_ldo_abb_ctrl_bits, + .setup_bits = &omap4_ldo_abb_setup_bits, + .ops = &omap4_ldo_abb_ops, + + .settling_time = 50, + .cycle_rate = 16, + .tranx_timeout = OMAP_ABB_TRANXDONE_TIMEOUT_US, +}; diff --git a/arch/arm/mach-omap2/lpddr2_elpida_data.c b/arch/arm/mach-omap2/lpddr2_elpida_data.c new file mode 100644 index 0000000..aee63f1 --- /dev/null +++ b/arch/arm/mach-omap2/lpddr2_elpida_data.c @@ -0,0 +1,111 @@ +/* + * LPDDR2 data as per JESD209-2 + * + * Copyright (C) 2010 Texas Instruments, Inc. + * + * Aneesh V <aneesh@ti.com> + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <mach/emif.h> +#include <mach/lpddr2-elpida.h> + +const struct lpddr2_timings lpddr2_elpida_timings_400_mhz = { + .max_freq = 400000000, + .RL = 6, + .tRPab = 21, + .tRCD = 18, + .tWR = 15, + .tRASmin = 42, + .tRRD = 10, + .tWTRx2 = 15, + .tXSR = 140, + .tXPx2 = 15, + .tRFCab = 130, + .tRTPx2 = 15, + .tCKE = 3, + .tCKESR = 15, + .tZQCS = 90, + .tZQCL = 360, + .tZQINIT = 1000, + .tDQSCKMAXx2 = 11, + .tRASmax = 70, + .tFAW = 50 +}; + +const struct lpddr2_timings lpddr2_elpida_timings_333_mhz = { + .max_freq = 333000000, + .RL = 5, + .tRPab = 21, + .tRCD = 18, + .tWR = 15, + .tRASmin = 42, + .tRRD = 10, + .tWTRx2 = 15, + .tXSR = 140, + .tXPx2 = 15, + .tRFCab = 130, + .tRTPx2 = 15, + .tCKE = 3, + .tCKESR = 15, + .tZQCS = 90, + .tZQCL = 360, + .tZQINIT = 1000, + .tDQSCKMAXx2 = 11, + .tRASmax = 70, + .tFAW = 50 +}; + +const struct lpddr2_timings lpddr2_elpida_timings_200_mhz = { + .max_freq = 200000000, + .RL = 3, + .tRPab = 21, + .tRCD = 18, + .tWR = 15, + .tRASmin = 42, + .tRRD = 10, + .tWTRx2 = 20, + .tXSR = 140, + .tXPx2 = 15, + .tRFCab = 130, + .tRTPx2 = 15, + .tCKE = 3, + .tCKESR = 15, + .tZQCS = 90, + .tZQCL = 360, + .tZQINIT = 1000, + .tDQSCKMAXx2 = 11, + .tRASmax = 70, + .tFAW = 50 +}; + +const struct lpddr2_min_tck lpddr2_elpida_min_tck = { + .tRL = 3, + .tRP_AB = 3, + .tRCD = 3, + .tWR = 3, + .tRAS_MIN = 3, + .tRRD = 2, + .tWTR = 2, + .tXP = 2, + .tRTP = 2, + .tCKE = 3, + .tCKESR = 3, + .tFAW = 8 +}; + +struct lpddr2_device_info lpddr2_elpida_2G_S4_dev = { + .device_timings = { + &lpddr2_elpida_timings_200_mhz, + &lpddr2_elpida_timings_333_mhz, + &lpddr2_elpida_timings_400_mhz + }, + .min_tck = &lpddr2_elpida_min_tck, + .type = LPDDR2_TYPE_S4, + .density = LPDDR2_DENSITY_2Gb, + .io_width = LPDDR2_IO_WIDTH_32 +}; diff --git a/arch/arm/mach-omap2/lpddr2_jedec_data.c b/arch/arm/mach-omap2/lpddr2_jedec_data.c new file mode 100644 index 0000000..e8b447c --- /dev/null +++ b/arch/arm/mach-omap2/lpddr2_jedec_data.c @@ -0,0 +1,132 @@ +/* + * LPDDR2 data as per JESD209-2 + * + * Copyright (C) 2010 Texas Instruments, Inc. + * + * Aneesh V <aneesh@ti.com> + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <mach/lpddr2-jedec.h> +#include <mach/emif.h> + +/* + * Organization and refresh requirements for LPDDR2 devices of different + * types and densities. Derived from JESD209-2 section 2.4 + */ +const struct lpddr2_addressing lpddr2_jedec_addressing_table[] = { + /* Banks tREFIx10 rowx32,rowx16 colx32,colx16 density */ + {BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_7, COL_8} }, /*64M*/ + {BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_8, COL_9} }, /*128M*/ + {BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_8, COL_9} }, /*256M*/ + {BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} }, /*512M*/ + {BANKS8, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} }, /*1GS4*/ + {BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_9, COL_10} }, /*2GS4*/ + {BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_10, COL_11} }, /*4G*/ + {BANKS8, T_REFI_3_9, {ROW_15, ROW_15}, {COL_10, COL_11} }, /*8G*/ + {BANKS4, T_REFI_7_8, {ROW_14, ROW_14}, {COL_9, COL_10} }, /*1GS2*/ + {BANKS4, T_REFI_3_9, {ROW_15, ROW_15}, {COL_9, COL_10} }, /*2GS2*/ +}; + +/* + * Base AC Timing values specified by JESD209-2 for 400MHz operation + * All devices will honour these timings at this frequency. + * Some devices may have better timings. Using these timings is safe when the + * timings are not available from the device data sheet. + */ +const struct lpddr2_timings lpddr2_jedec_timings_400_mhz = { + .max_freq = 400000000, + .RL = 6, + .tRPab = 21, + .tRCD = 18, + .tWR = 15, + .tRASmin = 42, + .tRRD = 10, + .tWTRx2 = 15, + .tXSR = 140, + .tXPx2 = 15, + .tRFCab = 130, + .tRTPx2 = 15, + .tCKE = 3, + .tCKESR = 15, + .tZQCS = 90, + .tZQCL = 360, + .tZQINIT = 1000, + .tDQSCKMAXx2 = 11, + .tRASmax = 70, + .tFAW = 50 +}; + +/* Base AC Timing values specified by JESD209-2 for 333 MHz operation */ +const struct lpddr2_timings lpddr2_jedec_timings_333_mhz = { + .max_freq = 333000000, + .RL = 5, + .tRPab = 21, + .tRCD = 18, + .tWR = 15, + .tRASmin = 42, + .tRRD = 10, + .tWTRx2 = 15, + .tXSR = 140, + .tXPx2 = 15, + .tRFCab = 130, + .tRTPx2 = 15, + .tCKE = 3, + .tCKESR = 15, + .tZQCS = 90, + .tZQCL = 360, + .tZQINIT = 1000, + .tDQSCKMAXx2 = 11, + .tRASmax = 70, + .tFAW = 50 +}; + +/* Base AC Timing values specified by JESD209-2 for 200 MHz operation */ +const struct lpddr2_timings lpddr2_jedec_timings_200_mhz = { + .max_freq = 200000000, + .RL = 3, + .tRPab = 21, + .tRCD = 18, + .tWR = 15, + .tRASmin = 42, + .tRRD = 10, + .tWTRx2 = 20, + .tXSR = 140, + .tXPx2 = 15, + .tRFCab = 130, + .tRTPx2 = 15, + .tCKE = 3, + .tCKESR = 15, + .tZQCS = 90, + .tZQCL = 360, + .tZQINIT = 1000, + .tDQSCKMAXx2 = 11, + .tRASmax = 70, + .tFAW = 50 +}; + +/* + * Min tCK values specified by JESD209-2 + * Min tCK specifies the minimum duration of some AC timing parameters in terms + * of the number of cycles. If the calculated number of cycles based on the + * absolute time value is less than the min tCK value, min tCK value should + * be used instead. This typically happens at low frequencies. + */ +const struct lpddr2_min_tck lpddr2_jedec_min_tck = { + .tRL = 3, + .tRP_AB = 3, + .tRCD = 3, + .tWR = 3, + .tRAS_MIN = 3, + .tRRD = 2, + .tWTR = 2, + .tXP = 2, + .tRTP = 2, + .tCKE = 3, + .tCKESR = 3, + .tFAW = 8 +}; diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 86d564a..74750bf 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -14,33 +14,39 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/slab.h> +#include <linux/delay.h> #include <linux/pm_runtime.h> #include <plat/mailbox.h> #include <mach/irqs.h> #define MAILBOX_REVISION 0x000 -#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m)) -#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m)) -#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m)) -#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u)) -#define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u)) +#define MAILBOX_SYSCONFIG 0x10 +#define MAILBOX_MESSAGE(m) (0x040 + 0x4 * (m)) +#define MAILBOX_FIFOSTATUS(m) (0x080 + 0x4 * (m)) +#define MAILBOX_MSGSTATUS(m) (0x0c0 + 0x4 * (m)) +#define MAILBOX_IRQSTATUS(u) (0x100 + 0x8 * (u)) +#define MAILBOX_IRQENABLE(u) (0x104 + 0x8 * (u)) -#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 10 * (u)) -#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 10 * (u)) -#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 10 * (u)) +#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u)) +#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u)) +#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u)) #define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m))) #define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1)) +#define MAILBOX_SOFTRESET 1 -#define MBOX_REG_SIZE 0x120 - -#define OMAP4_MBOX_REG_SIZE 0x130 - -#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32)) -#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32)) +#define MBOX_NUM_USER 2 +#define OMAP4_MBOX_NUM_USER 3 +#define MBOX_NR_REGS 2 +#define OMAP4_MBOX_NR_REGS 3 static void __iomem *mbox_base; +static u32 *mbox_ctx; +static int nr_mbox_users; +static bool context_saved; + struct omap_mbox2_fifo { unsigned long msg; unsigned long fifo_stat; @@ -54,7 +60,6 @@ struct omap_mbox2_priv { unsigned long irqstatus; u32 newmsg_bit; u32 notfull_bit; - u32 ctx[OMAP4_MBOX_NR_REGS]; unsigned long irqdisable; }; @@ -71,14 +76,66 @@ static inline void mbox_write_reg(u32 val, size_t ofs) __raw_writel(val, mbox_base + ofs); } +static void omap2_mbox_save_ctx(struct omap_mbox *mbox) +{ + int i; + + if (context_saved) + return; + + /* Save irqs per user */ + for (i = 0; i < nr_mbox_users; i++) { + if (cpu_is_omap44xx()) + mbox_ctx[i] = mbox_read_reg(OMAP4_MAILBOX_IRQENABLE(i)); + else + mbox_ctx[i] = mbox_read_reg(MAILBOX_IRQENABLE(i)); + + dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, + i, mbox_ctx[i]); + } + + context_saved = true; +} + +static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) +{ + int i; + + if (!context_saved) + return; + + /* Restore irqs per user */ + for (i = 0; i < nr_mbox_users; i++) { + if (cpu_is_omap44xx()) + mbox_write_reg(mbox_ctx[i], OMAP4_MAILBOX_IRQENABLE(i)); + else + mbox_write_reg(mbox_ctx[i], MAILBOX_IRQENABLE(i)); + + dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, + i, mbox_ctx[i]); + } + + context_saved = false; +} + /* Mailbox H/W preparations */ static int omap2_mbox_startup(struct omap_mbox *mbox) { u32 l; + u32 max_iter = 100; pm_runtime_enable(mbox->dev->parent); pm_runtime_get_sync(mbox->dev->parent); + mbox_write_reg(MAILBOX_SOFTRESET, MAILBOX_SYSCONFIG); + while (mbox_read_reg(MAILBOX_SYSCONFIG) & MAILBOX_SOFTRESET) { + if (WARN_ON(!max_iter--)) + break; + udelay(1); + } + + omap2_mbox_restore_ctx(mbox); + l = mbox_read_reg(MAILBOX_REVISION); pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f)); @@ -89,6 +146,7 @@ static int omap2_mbox_startup(struct omap_mbox *mbox) static void omap2_mbox_shutdown(struct omap_mbox *mbox) { + omap2_mbox_save_ctx(mbox); pm_runtime_put_sync(mbox->dev->parent); pm_runtime_disable(mbox->dev->parent); } @@ -169,40 +227,6 @@ static int omap2_mbox_is_irq(struct omap_mbox *mbox, return (int)(enable & status & bit); } -static void omap2_mbox_save_ctx(struct omap_mbox *mbox) -{ - int i; - struct omap_mbox2_priv *p = mbox->priv; - int nr_regs; - if (cpu_is_omap44xx()) - nr_regs = OMAP4_MBOX_NR_REGS; - else - nr_regs = MBOX_NR_REGS; - for (i = 0; i < nr_regs; i++) { - p->ctx[i] = mbox_read_reg(i * sizeof(u32)); - - dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, - i, p->ctx[i]); - } -} - -static void omap2_mbox_restore_ctx(struct omap_mbox *mbox) -{ - int i; - struct omap_mbox2_priv *p = mbox->priv; - int nr_regs; - if (cpu_is_omap44xx()) - nr_regs = OMAP4_MBOX_NR_REGS; - else - nr_regs = MBOX_NR_REGS; - for (i = 0; i < nr_regs; i++) { - mbox_write_reg(p->ctx[i], i * sizeof(u32)); - - dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__, - i, p->ctx[i]); - } -} - static struct omap_mbox_ops omap2_mbox_ops = { .type = OMAP_MBOX_TYPE2, .startup = omap2_mbox_startup, @@ -373,17 +397,31 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev) } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENODEV; + mbox_base = ioremap(mem->start, resource_size(mem)); if (!mbox_base) return -ENOMEM; - ret = omap_mbox_register(&pdev->dev, list); - if (ret) { - iounmap(mbox_base); - return ret; + nr_mbox_users = cpu_is_omap44xx() ? OMAP4_MBOX_NUM_USER : MBOX_NUM_USER; + mbox_ctx = kzalloc(sizeof(u32) * nr_mbox_users, GFP_KERNEL); + if (!mbox_ctx) { + ret = -ENOMEM; + goto unmap_base; } + ret = omap_mbox_register(&pdev->dev, list); + if (ret) + goto free_ctx; + return 0; + +free_ctx: + kfree(mbox_ctx); +unmap_base: + iounmap(mbox_base); + return ret; } static int __devexit omap2_mbox_remove(struct platform_device *pdev) diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index 4a6ef6a..6afbc0d 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -71,9 +71,9 @@ int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id) mcbsp = id_to_mcbsp_ptr(id); if (fck_src_id == MCBSP_CLKS_PAD_SRC) - fck_src_name = "pad_fck"; + fck_src_name = mcbsp->pdata->clks_pad_src; else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) - fck_src_name = "prcm_fck"; + fck_src_name = mcbsp->pdata->clks_prcm_src; else return -EINVAL; @@ -129,12 +129,21 @@ static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused) pdata->mcbsp_config_type = oh->class->rev; if (oh->class->rev == MCBSP_CONFIG_TYPE3) { + strcpy(pdata->clks_pad_src, "pad_fck"); + strcpy(pdata->clks_prcm_src, "prcm_fck"); + if (id == 2) /* The FIFO has 1024 + 256 locations */ pdata->buffer_size = 0x500; else /* The FIFO has 128 locations */ pdata->buffer_size = 0x80; + } else if (oh->class->rev == MCBSP_CONFIG_TYPE4) { + strcpy(pdata->clks_pad_src, "pad_clks_ck"); + sprintf(pdata->clks_prcm_src, "mcbsp%d_sync_mux_ck", id); + + /* The FIFO has 128 locations for all instances */ + pdata->buffer_size = 0x80; } oh_device[0] = oh; diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index c7fb22a..c7d0b21 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -118,10 +118,8 @@ static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition, } } - if (found == 0) { - pr_err("%s: Could not set gpio%i\n", __func__, gpio); + if (found == 0) return -ENODEV; - } if (found > 1) { pr_info("%s: Multiple gpio paths (%d) for gpio%i\n", __func__, @@ -153,6 +151,8 @@ int __init omap_mux_init_gpio(int gpio, int val) return ret; } + pr_err("%s: Could not set gpio%i\n", __func__, gpio); + return -ENODEV; } @@ -210,8 +210,6 @@ static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition, return -EINVAL; } - pr_err("%s: Could not find signal %s\n", __func__, muxname); - return -ENODEV; } @@ -234,6 +232,8 @@ omap_mux_get_by_name(const char *muxname, return mux_mode; } + pr_err("%s: Could not find signal %s\n", __func__, muxname); + return -ENODEV; } @@ -351,6 +351,36 @@ err1: return NULL; } +/** + * omap_hwmod_mux_get_wake_status - omap hwmod check pad wakeup + * @hmux: Pads for a hwmod + * + * Gets the wakeup status of given pad from omap-hwmod. + * Returns true if wakeup event is set for pad else false + * if wakeup is not occured or pads are not avialable. + */ +int omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux) +{ + int i; + unsigned int val; + u8 ret = false; + + for (i = 0; i < hmux->nr_pads; i++) { + struct omap_device_pad *pad = &hmux->pads[i]; + + if (pad->flags & OMAP_DEVICE_PAD_WAKEUP) { + val = omap_mux_read(pad->partition, + pad->mux->reg_offset); + if (val & OMAP_WAKEUP_EVENT) { + ret = true; + break; + } + } + } + + return ret; +} + /* Assumes the calling function takes care of locking */ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) { @@ -906,7 +936,7 @@ static struct omap_mux *omap_mux_get_by_gpio( } /* Needed for dynamic muxing of GPIO pins for off-idle */ -u16 omap_mux_get_gpio(int gpio) +struct omap_mux *omap_mux_get_gpio(int gpio) { struct omap_mux_partition *partition; struct omap_mux *m = NULL; @@ -914,13 +944,10 @@ u16 omap_mux_get_gpio(int gpio) list_for_each_entry(partition, &mux_partitions, node) { m = omap_mux_get_by_gpio(partition, gpio); if (m) - return omap_mux_read(partition, m->reg_offset); + return m; } - if (!m || m->reg_offset == OMAP_MUX_TERMINATOR) - pr_err("%s: Could not get gpio%i\n", __func__, gpio); - - return OMAP_MUX_TERMINATOR; + return NULL; } /* Needed for dynamic muxing of GPIO pins for off-idle */ @@ -941,6 +968,55 @@ void omap_mux_set_gpio(u16 val, int gpio) pr_err("%s: Could not set gpio%i\n", __func__, gpio); } +bool omap_mux_get_wakeupevent(struct omap_mux *m) +{ + u16 val; + if (IS_ERR_OR_NULL(m) || !cpu_is_omap44xx()) + return false; + + val = omap_mux_read(m->partition, m->reg_offset); + return val & OMAP_WAKEUP_EVENT; +} + +/* Has no locking, don't use on a pad that is remuxed (by hwmod or otherwise) */ +bool omap_mux_get_wakeupenable(struct omap_mux *m) +{ + u16 val; + if (IS_ERR_OR_NULL(m)) + return false; + + val = omap_mux_read(m->partition, m->reg_offset); + return val & OMAP_PIN_OFF_WAKEUPENABLE; +} + +/* Has no locking, don't use on a pad that is remuxed (by hwmod or otherwise) */ +int omap_mux_set_wakeupenable(struct omap_mux *m) +{ + u16 val; + if (IS_ERR_OR_NULL(m)) + return -EINVAL; + + val = omap_mux_read(m->partition, m->reg_offset); + val |= OMAP_PIN_OFF_WAKEUPENABLE; + omap_mux_write(m->partition, val, m->reg_offset); + + return 0; +} + +/* Has no locking, don't use on a pad that is remuxed (by hwmod or otherwise) */ +int omap_mux_clear_wakeupenable(struct omap_mux *m) +{ + u16 val; + if (IS_ERR_OR_NULL(m)) + return -EINVAL; + + val = omap_mux_read(m->partition, m->reg_offset); + val &= ~OMAP_PIN_OFF_WAKEUPENABLE; + omap_mux_write(m->partition, val, m->reg_offset); + + return 0; +} + static struct omap_mux * __init omap_mux_list_add( struct omap_mux_partition *partition, struct omap_mux *src) @@ -954,6 +1030,7 @@ static struct omap_mux * __init omap_mux_list_add( m = &entry->mux; entry->mux = *src; + m->partition = partition; #ifdef CONFIG_OMAP_MUX if (omap_mux_copy_names(src, m)) { diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h index 2132308..e631b5e 100644 --- a/arch/arm/mach-omap2/mux.h +++ b/arch/arm/mach-omap2/mux.h @@ -131,6 +131,7 @@ struct omap_mux_partition { struct omap_mux { u16 reg_offset; u16 gpio; + struct omap_mux_partition *partition; #ifdef CONFIG_OMAP_MUX char *muxnames[OMAP_MUX_NR_MODES]; #ifdef CONFIG_DEBUG_FS @@ -225,8 +226,21 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads); */ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state); +/** + * omap_hwmod_mux_get_wake_status - omap hwmod check pad wakeup + * @hmux: Pads for a hwmod + * + * Called only from omap_hwmod.c, do not use. + */ +int omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux); #else +static inline int +omap_hwmod_mux_get_wake_status(struct omap_hwmod_mux_info *hmux) +{ + return 0; +} + static inline int omap_mux_init_gpio(int gpio, int val) { return 0; @@ -251,11 +265,31 @@ static struct omap_board_mux *board_mux __initdata __maybe_unused; #endif /** - * omap_mux_get_gpio() - get mux register value based on GPIO number + * omap_mux_get_gpio() - get mux struct based on GPIO number * @gpio: GPIO number * */ -u16 omap_mux_get_gpio(int gpio); +struct omap_mux *omap_mux_get_gpio(int gpio); + +/** omap_mux_set_wakeupenable() - set the wakeupenable bit on a mux struct + * @m: mux struct + */ +int omap_mux_set_wakeupenable(struct omap_mux *m); + +/** omap_mux_clear_wakeupenable() - clear the wakeupenable bit on a mux struct + * @m: mux struct + */ +int omap_mux_clear_wakeupenable(struct omap_mux *m); + +/** omap_mux_get_wakeupenable() - get the wakeupenable bit from a mux struct + * @m: mux struct + */ +bool omap_mux_get_wakeupenable(struct omap_mux *m); + +/** omap_mux_get_wakeupevent() - get the wakeupevent bit from a mux struct + * @m: mux struct + */ +bool omap_mux_get_wakeupevent(struct omap_mux *m); /** * omap_mux_set_gpio() - set mux register value based on GPIO number diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c index 4976b93..f69cd5c 100644 --- a/arch/arm/mach-omap2/omap-hotplug.c +++ b/arch/arm/mach-omap2/omap-hotplug.c @@ -19,7 +19,13 @@ #include <linux/smp.h> #include <asm/cacheflush.h> +#include <asm/hardware/gic.h> + #include <mach/omap4-common.h> +#include <mach/omap-wakeupgen.h> + +#include "powerdomain.h" +#include "clockdomain.h" int platform_cpu_kill(unsigned int cpu) { @@ -32,6 +38,12 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { + unsigned int this_cpu; + static struct clockdomain *cpu1_clkdm; + + if (!cpu1_clkdm) + cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); + flush_cache_all(); dsb(); @@ -39,18 +51,26 @@ void platform_cpu_die(unsigned int cpu) * we're ready for shutdown now, so do it */ if (omap_modify_auxcoreboot0(0x0, 0x200) != 0x0) - printk(KERN_CRIT "Secure clear status failed\n"); + pr_err("Secure clear status failed\n"); for (;;) { /* - * Execute WFI + * Enter into low power state + * clear all interrupt wakeup sources */ - do_wfi(); - - if (omap_read_auxcoreboot0() == cpu) { + omap_wakeupgen_irqmask_all(cpu, 1); + gic_cpu_disable(); + omap4_enter_lowpower(cpu, PWRDM_POWER_OFF); + this_cpu = hard_smp_processor_id(); + if (omap_read_auxcoreboot0() == this_cpu) { /* * OK, proper wakeup, we're done */ + omap_wakeupgen_irqmask_all(this_cpu, 0); + gic_cpu_enable(); + + /* Restore clockdomain to hardware supervised */ + clkdm_allow_idle(cpu1_clkdm); break; } pr_debug("CPU%u: spurious wakeup call\n", cpu); diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index 3fc5dc7..6965b4d 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -11,9 +11,12 @@ */ #include <linux/platform_device.h> +#include <linux/err.h> #include <plat/iommu.h> -#include <plat/irqs.h> +#include <plat/omap_device.h> +#include <plat/omap_hwmod.h> + struct iommu_device { resource_size_t base; @@ -21,145 +24,118 @@ struct iommu_device { struct iommu_platform_data pdata; struct resource res[2]; }; -static struct iommu_device *devices; +static struct iommu_platform_data *devices_data; static int num_iommu_devices; #ifdef CONFIG_ARCH_OMAP3 -static struct iommu_device omap3_devices[] = { +static struct iommu_platform_data omap3_devices_data[] = { { - .base = 0x480bd400, - .irq = 24, - .pdata = { - .name = "isp", - .nr_tlb_entries = 8, - .clk_name = "cam_ick", - .da_start = 0x0, - .da_end = 0xFFFFF000, - }, + .name = "isp", + .oh_name = "isp", + .nr_tlb_entries = 8, + .da_start = 0x0, + .da_end = 0xFFFFF000, }, #if defined(CONFIG_OMAP_IOMMU_IVA2) { - .base = 0x5d000000, - .irq = 28, - .pdata = { - .name = "iva2", - .nr_tlb_entries = 32, - .clk_name = "iva2_ck", - .da_start = 0x11000000, - .da_end = 0xFFFFF000, - }, + .name = "iva2", + .oh_name = "dsp", + .nr_tlb_entries = 32, + .da_start = 0x11000000, + .da_end = 0xFFFFF000, }, #endif }; -#define NR_OMAP3_IOMMU_DEVICES ARRAY_SIZE(omap3_devices) -static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES]; +#define NR_OMAP3_IOMMU_DEVICES ARRAY_SIZE(omap3_devices_data) #else -#define omap3_devices NULL +#define omap3_devices_data NULL #define NR_OMAP3_IOMMU_DEVICES 0 -#define omap3_iommu_pdev NULL #endif #ifdef CONFIG_ARCH_OMAP4 -static struct iommu_device omap4_devices[] = { +static struct iommu_platform_data omap4_devices_data[] = { { - .base = OMAP4_MMU1_BASE, - .irq = OMAP44XX_IRQ_DUCATI_MMU, - .pdata = { - .name = "ducati", - .nr_tlb_entries = 32, - .clk_name = "ducati_ick", - .da_start = 0x0, - .da_end = 0xFFFFF000, - }, + .name = "ducati", + .oh_name = "ipu", + .nr_tlb_entries = 32, + .da_start = 0x0, + .da_end = 0xFFFFF000, }, -#if defined(CONFIG_MPU_TESLA_IOMMU) { - .base = OMAP4_MMU2_BASE, - .irq = INT_44XX_DSP_MMU, - .pdata = { - .name = "tesla", - .nr_tlb_entries = 32, - .clk_name = "tesla_ick", - .da_start = 0x0, - .da_end = 0xFFFFF000, - }, + .name = "tesla", + .oh_name = "dsp", + .nr_tlb_entries = 32, + .da_start = 0x0, + .da_end = 0xFFFFF000, }, -#endif }; -#define NR_OMAP4_IOMMU_DEVICES ARRAY_SIZE(omap4_devices) -static struct platform_device *omap4_iommu_pdev[NR_OMAP4_IOMMU_DEVICES]; +#define NR_OMAP4_IOMMU_DEVICES ARRAY_SIZE(omap4_devices_data) #else -#define omap4_devices NULL +#define omap4_devices_data NULL #define NR_OMAP4_IOMMU_DEVICES 0 -#define omap4_iommu_pdev NULL #endif -static struct platform_device **omap_iommu_pdev; +static struct omap_device_pm_latency omap_iommu_latency[] = { + [0] = { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +int iommu_get_plat_data_size(void) +{ + return num_iommu_devices; +} +EXPORT_SYMBOL(iommu_get_plat_data_size); + +struct iommu_platform_data *iommu_get_device_data(void) +{ + return devices_data; +} static int __init omap_iommu_init(void) { - int i, err; - struct resource res[] = { - { .flags = IORESOURCE_MEM }, - { .flags = IORESOURCE_IRQ }, - }; + int i, ohl_cnt; + struct omap_hwmod *oh; + struct omap_device *od; + struct omap_device_pm_latency *ohl; if (cpu_is_omap34xx()) { - devices = omap3_devices; - omap_iommu_pdev = omap3_iommu_pdev; + devices_data = omap3_devices_data; num_iommu_devices = NR_OMAP3_IOMMU_DEVICES; } else if (cpu_is_omap44xx()) { - devices = omap4_devices; - omap_iommu_pdev = omap4_iommu_pdev; + devices_data = omap4_devices_data; num_iommu_devices = NR_OMAP4_IOMMU_DEVICES; } else return -ENODEV; + ohl = omap_iommu_latency; + ohl_cnt = ARRAY_SIZE(omap_iommu_latency); + for (i = 0; i < num_iommu_devices; i++) { - struct platform_device *pdev; - const struct iommu_device *d = &devices[i]; + struct iommu_platform_data *data = &devices_data[i]; - pdev = platform_device_alloc("omap-iommu", i); - if (!pdev) { - err = -ENOMEM; - goto err_out; - } + oh = omap_hwmod_lookup(data->oh_name); + data->io_base = oh->_mpu_rt_va; + data->irq = oh->mpu_irqs[0].irq; - res[0].start = d->base; - res[0].end = d->base + MMU_REG_SIZE - 1; - res[1].start = res[1].end = d->irq; - - err = platform_device_add_resources(pdev, res, - ARRAY_SIZE(res)); - if (err) - goto err_out; - err = platform_device_add_data(pdev, &d->pdata, - sizeof(d->pdata)); - if (err) - goto err_out; - err = platform_device_add(pdev); - if (err) - goto err_out; - omap_iommu_pdev[i] = pdev; + if (!oh) { + pr_err("%s: could not look up %s\n", __func__, + data->oh_name); + continue; + } + od = omap_device_build("omap-iommu", i, oh, + data, sizeof(*data), + ohl, ohl_cnt, false); + WARN(IS_ERR(od), "Could not build omap_device" + "for %s %s\n", "omap-iommu", data->oh_name); } return 0; - -err_out: - while (i--) - platform_device_put(omap_iommu_pdev[i]); - return err; } module_init(omap_iommu_init); -static void __exit omap_iommu_exit(void) -{ - int i; - - for (i = 0; i < num_iommu_devices; i++) - platform_device_unregister(omap_iommu_pdev[i]); -} -module_exit(omap_iommu_exit); - MODULE_AUTHOR("Hiroshi DOYU"); +MODULE_AUTHOR("Hari Kanigeri"); MODULE_DESCRIPTION("omap iommu: omap device registration"); MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index ecfe93c..40e425a 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -17,7 +17,9 @@ */ #include <linux/init.h> #include <linux/device.h> +#include <linux/delay.h> #include <linux/smp.h> +#include <linux/hrtimer.h> #include <linux/io.h> #include <asm/cacheflush.h> @@ -26,13 +28,27 @@ #include <mach/hardware.h> #include <mach/omap4-common.h> +#include "clockdomain.h" + /* SCU base address */ static void __iomem *scu_base; static DEFINE_SPINLOCK(boot_lock); + +void __iomem *omap4_get_scu_base(void) +{ + return scu_base; +} + void __cpuinit platform_secondary_init(unsigned int cpu) { + /* Enable NS access to SMP bit for this CPU on HS devices */ + if (cpu_is_omap443x() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) + omap4_secure_dispatcher(PPA_SERVICE_DEFAULT_POR_NS_SMP, + FLAG_START_CRITICAL, + 0, 0, 0, 0, 0); + /* * If any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled @@ -49,6 +65,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu) int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { + static struct clockdomain *cpu1_clkdm; + static bool booted; + /* * Set synchronisation state between this boot processor * and the secondary one @@ -64,7 +83,57 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) omap_modify_auxcoreboot0(0x200, 0xfffffdff); flush_cache_all(); smp_wmb(); - gic_raise_softirq(cpumask_of(cpu), 1); + + if (!cpu1_clkdm) + cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); + + /* + * The SGI(Software Generated Interrupts) are not wakeup capable + * from low power states. This is known limitation on OMAP4 and + * needs to be worked around by using software forced clockdomain + * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to + * software force wakeup. After the wakeup, CPU1 restores its + * clockdomain hardware supervised mode. + * More details can be found in OMAP4430 TRM - Version J + * Section : + * 4.3.4.2 Power States of CPU0 and CPU1 + */ + if (booted) { + /* + * GIC distributor control register has changed between + * CortexA9 r1pX and r2pX. The Control Register secure + * banked version is now composed of 2 bits: + * bit 0 == Secure Enable + * bit 1 == Non-Secure Enable + * The Non-Secure banked register has not changed + * Because the ROM Code is based on the r1pX GIC, the CPU1 + * GIC restoration will cause a problem to CPU0 Non-Secure SW. + * The workaround must be: + * 1) Before doing the CPU1 wakeup, CPU0 must disable + * the GIC distributor + * 2) CPU1 must re-enable the GIC distributor on + * it's wakeup path. + */ + if (!cpu_is_omap443x()) { + local_irq_disable(); + gic_dist_disable(); + } + + clkdm_wakeup(cpu1_clkdm); + + if (!cpu_is_omap443x()) { + while (gic_dist_disabled()) { + udelay(1); + cpu_relax(); + } + gic_timer_retrigger(); + local_irq_enable(); + } + + } else { + dsb_sev(); + booted = true; + } /* * Now the secondary core is starting up let it run its diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c new file mode 100644 index 0000000..7567ee6 --- /dev/null +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -0,0 +1,311 @@ +/* + * OMAP WakeupGen Source file + * + * The WakeupGen unit is responsible for generating wakeup event from the + * incoming interrupts and enable bits. The WakeupGen is implemented in MPU + * always-On power domain. The WakeupGen consists of two sub-units, one for + * each CPU and manages only SPI interrupts. Hardware requirements is that + * the GIC and WakeupGen should be kept in sync for proper operation. + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Written by Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/platform_device.h> + +#include <asm/hardware/gic.h> + +#include <mach/omap-wakeupgen.h> +#include <mach/omap4-common.h> + +#include "omap4-sar-layout.h" + +#define NR_BANKS 4 +#define MAX_IRQS 128 +#define WKG_MASK_ALL 0x00000000 +#define WKG_UNMASK_ALL 0xffffffff +#define CPU_ENA_OFFSET 0x400 +#define CPU0_ID 0x0 +#define CPU1_ID 0x1 + +/* WakeupGen Base addres */ +static void __iomem *wakeupgen_base; +static void __iomem *sar_base; +static DEFINE_PER_CPU(u32 [NR_BANKS], irqmasks); +static DEFINE_SPINLOCK(wakeupgen_lock); + +/* + * Static helper functions + */ + +static inline u32 wakeupgen_readl(u8 idx, u32 cpu) +{ + return __raw_readl(wakeupgen_base + OMAP_WKG_ENB_A_0 + + (cpu * CPU_ENA_OFFSET) + (idx * 4)); +} + +static inline void wakeupgen_writel(u32 val, u8 idx, u32 cpu) +{ + __raw_writel(val, wakeupgen_base + OMAP_WKG_ENB_A_0 + + (cpu * CPU_ENA_OFFSET) + (idx * 4)); +} + +static inline void sar_writel(u32 val, u32 offset, u8 idx) +{ + __raw_writel(val, sar_base + offset + (idx * 4)); +} + +static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg) +{ + u8 i; + + for (i = 0; i < NR_BANKS; i++) + wakeupgen_writel(reg, i, cpu); +} + +static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index) +{ + unsigned int spi_irq; + + /* + * PPIs and SGIs are not supported + */ + if (irq < OMAP44XX_IRQ_GIC_START) + return -EINVAL; + + /* + * Subtract the GIC offset + */ + spi_irq = irq - OMAP44XX_IRQ_GIC_START; + if (spi_irq > MAX_IRQS) { + pr_err("omap wakeupGen: Invalid IRQ%d\n", irq); + return -EINVAL; + } + + /* + * Each wakeup gen register controls 32 + * interrupts. i.e 1 bit per SPI IRQ + */ + *reg_index = spi_irq >> 5; + *bit_posn = spi_irq %= 32; + + return 0; +} + +static void _wakeupgen_clear(unsigned int irq, unsigned int cpu) +{ + u32 val, bit_number; + u8 i; + + if (_wakeupgen_get_irq_info(irq, &bit_number, &i)) + return; + + val = wakeupgen_readl(i, cpu); + val &= ~BIT(bit_number); + wakeupgen_writel(val, i, cpu); +} + +static void _wakeupgen_set(unsigned int irq, unsigned int cpu) +{ + u32 val, bit_number; + u8 i; + + if (_wakeupgen_get_irq_info(irq, &bit_number, &i)) + return; + + val = wakeupgen_readl(i, cpu); + val |= BIT(bit_number); + wakeupgen_writel(val, i, cpu); +} + +static void _wakeupgen_save_masks(unsigned int cpu) +{ + u8 i; + + for (i = 0; i < NR_BANKS; i++) + per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu); +} + +static void _wakeupgen_restore_masks(unsigned int cpu) +{ + u8 i; + + for (i = 0; i < NR_BANKS; i++) + wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu); +} + +/* + * Architecture specific Mask extensiom + */ +static void wakeupgen_mask(struct irq_data *d) +{ + spin_lock(&wakeupgen_lock); + _wakeupgen_clear(d->irq, d->node); + spin_unlock(&wakeupgen_lock); +} + +/* + * Architecture specific Unmask extensiom + */ +static void wakeupgen_unmask(struct irq_data *d) +{ + spin_lock(&wakeupgen_lock); + _wakeupgen_set(d->irq, d->node); + spin_unlock(&wakeupgen_lock); +} + +/** + * omap_wakeupgen_irqmask_all() - Mask or unmask interrupts + * @cpu - CPU ID + * @set - The IRQ register mask. + * 0 = Mask all interrupts on the 'cpu' + * 1 = Unmask all interrupts on the 'cpu' + * + * Ensure that the initial mask is maintained. This is faster than + * iterating through GIC rgeisters to arrive at the correct masks + */ +void omap_wakeupgen_irqmask_all(unsigned int cpu, unsigned int set) +{ + if (omap_rev() == OMAP4430_REV_ES1_0) + return; + + spin_lock(&wakeupgen_lock); + if (set) { + _wakeupgen_save_masks(cpu); + _wakeupgen_set_all(cpu, WKG_MASK_ALL); + } else { + _wakeupgen_set_all(cpu, WKG_UNMASK_ALL); + _wakeupgen_restore_masks(cpu); + } + spin_unlock(&wakeupgen_lock); +} + +#ifdef CONFIG_PM +/* + * Masking wakeup irqs is handled by the IRQCHIP_MASK_ON_SUSPEND flag, + * so no action is necessary in set_wake, but implement an empty handler + * here to prevent enable_irq_wake() returning an error. + */ +static int wakeupgen_set_wake(struct irq_data *d, unsigned int on) +{ + return 0; +} +#else +#define wakeupgen_set_wake NULL +#endif + +/* + * Initialse the wakeupgen module + */ +int __init omap_wakeupgen_init(void) +{ + u8 i; + + /* Not supported on on OMAP4 ES1.0 silicon */ + if (omap_rev() == OMAP4430_REV_ES1_0) { + WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n"); + return -EPERM; + } + + /* Static mapping, never released */ + wakeupgen_base = ioremap(OMAP44XX_WKUPGEN_BASE, SZ_4K); + if (WARN_ON(!wakeupgen_base)) + return -ENODEV; + + /* Clear all IRQ bitmasks at wakeupGen level */ + for (i = 0; i < NR_BANKS; i++) { + wakeupgen_writel(0, i, CPU0_ID); + wakeupgen_writel(0, i, CPU1_ID); + } + + /* + * Override gic architecture specific fucntioms to add + * OMAP WakeupGen interrupt controller along with GIC + */ + gic_arch_extn.irq_mask = wakeupgen_mask; + gic_arch_extn.irq_unmask = wakeupgen_unmask; + gic_arch_extn.irq_set_wake = wakeupgen_set_wake; + gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND; + + return 0; +} + +/** + * omap_wakeupgen_save() - WakeupGen context save function + * + * Save WakewupGen context in SAR BANK3. Restore is done by ROM code. + * WakeupGen IP is integrated along with GIC to manage the + * interrupt wakeups from CPU low power states. It's located in + * always ON power domain. It manages masking/unmasking of + * Shared peripheral interrupts(SPI).So the interrupt enable/disable + * control should be in sync and consistent at WakeupGen and GIC so + * that interrupts are not lost. Hence GIC and WakeupGen are saved + * and restored together. + + * During normal operation, WakeupGen delivers external interrupts + * directly to the GIC. When the CPU asserts StandbyWFI, indicating + * it wants to enter lowpower state, the Standby Controller checks + * with the WakeupGen unit using the idlereq/idleack handshake to make + * sure there is no incoming interrupts. + */ + +void omap_wakeupgen_save(void) +{ + u8 i; + u32 val; + + if (omap_rev() == OMAP4430_REV_ES1_0) + return; + + if (!sar_base) + sar_base = omap4_get_sar_ram_base(); + + for (i = 0; i < NR_BANKS; i++) { + /* Save the CPUx interrupt mask for IRQ 0 to 127 */ + val = wakeupgen_readl(i, 0); + sar_writel(val, WAKEUPGENENB_OFFSET_CPU0, i); + val = wakeupgen_readl(i, 1); + sar_writel(val, WAKEUPGENENB_OFFSET_CPU1, i); + + /* + * Disable the secure interrupts for CPUx. The restore + * code blindly restores secure and non-secure interrupt + * masks from SAR RAM. Secure interrupts are not suppose + * to be enabled from HLOS. So overwrite the SAR location + * so that the secure interrupt remains disabled. + */ + sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU0, i); + sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU1, i); + } + + /* Save AuxBoot* registers */ + val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + __raw_writel(val, sar_base + AUXCOREBOOT0_OFFSET); + val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + __raw_writel(val, sar_base + AUXCOREBOOT1_OFFSET); + + /* Save SyncReq generation logic */ + val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + __raw_writel(val, sar_base + AUXCOREBOOT0_OFFSET); + val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + __raw_writel(val, sar_base + AUXCOREBOOT1_OFFSET); + + /* Save SyncReq generation logic */ + val = __raw_readl(wakeupgen_base + OMAP_PTMSYNCREQ_MASK); + __raw_writel(val, sar_base + PTMSYNCREQ_MASK_OFFSET); + val = __raw_readl(wakeupgen_base + OMAP_PTMSYNCREQ_EN); + __raw_writel(val, sar_base + PTMSYNCREQ_EN_OFFSET); + + /* Set the Backup Bit Mask status */ + val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET); + val |= SAR_BACKUP_STATUS_WAKEUPGEN; + __raw_writel(val, sar_base + SAR_BACKUP_STATUS_OFFSET); +} diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c new file mode 100644 index 0000000..7c5a6f9 --- /dev/null +++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c @@ -0,0 +1,439 @@ +/* + * OMAP2PLUS cpufreq driver + * + * CPU frequency scaling for OMAP using OPP information + * + * Copyright (C) 2005 Nokia Corporation + * Written by Tony Lindgren <tony@atomide.com> + * + * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King + * + * Copyright (C) 2007-2011 Texas Instruments, Inc. + * Updated to support OMAP3 + * Rajendra Nayak <rnayak@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/opp.h> +#include <linux/cpu.h> +#include <linux/platform_device.h> + +#include <asm/system.h> +#include <asm/smp_plat.h> +#include <asm/cpu.h> + +#include <plat/clock.h> +#include <plat/omap-pm.h> +#include <plat/common.h> + +#include <mach/hardware.h> + +#include "dvfs.h" + +#ifdef CONFIG_SMP +struct lpj_info { + unsigned long ref; + unsigned int freq; +}; + +static DEFINE_PER_CPU(struct lpj_info, lpj_ref); +static struct lpj_info global_lpj_ref; +#endif + +static struct cpufreq_frequency_table *freq_table; +static atomic_t freq_table_users = ATOMIC_INIT(0); +static struct clk *mpu_clk; +static char *mpu_clk_name; +static struct device *mpu_dev; +static DEFINE_MUTEX(omap_cpufreq_lock); + +static unsigned int max_thermal; +static unsigned int max_freq; +static unsigned int current_target_freq; +static bool omap_cpufreq_ready; +static bool omap_cpufreq_suspended; + +static unsigned int omap_getspeed(unsigned int cpu) +{ + unsigned long rate; + + if (cpu >= NR_CPUS) + return 0; + + rate = clk_get_rate(mpu_clk) / 1000; + return rate; +} + +static int omap_cpufreq_scale(unsigned int target_freq, unsigned int cur_freq) +{ + unsigned int i; + int ret; + struct cpufreq_freqs freqs; + + freqs.new = target_freq; + freqs.old = omap_getspeed(0); + + /* + * If the new frequency is more than the thermal max allowed + * frequency, go ahead and scale the mpu device to proper frequency. + */ + if (freqs.new > max_thermal) + freqs.new = max_thermal; + + if ((freqs.old == freqs.new) && (cur_freq = freqs.new)) + return 0; + + get_online_cpus(); + + /* notifiers */ + for_each_online_cpu(freqs.cpu) + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + +#ifdef CONFIG_CPU_FREQ_DEBUG + pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); +#endif + + ret = omap_device_scale(mpu_dev, mpu_dev, freqs.new * 1000); + + freqs.new = omap_getspeed(0); + +#ifdef CONFIG_SMP + /* + * Note that loops_per_jiffy is not updated on SMP systems in + * cpufreq driver. So, update the per-CPU loops_per_jiffy value + * on frequency transition. We need to update all dependent CPUs. + */ + for_each_possible_cpu(i) { + struct lpj_info *lpj = &per_cpu(lpj_ref, i); + if (!lpj->freq) { + lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy; + lpj->freq = freqs.old; + } + + per_cpu(cpu_data, i).loops_per_jiffy = + cpufreq_scale(lpj->ref, lpj->freq, freqs.new); + } + + /* And don't forget to adjust the global one */ + if (!global_lpj_ref.freq) { + global_lpj_ref.ref = loops_per_jiffy; + global_lpj_ref.freq = freqs.old; + } + loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, + freqs.new); +#endif + + /* notifiers */ + for_each_online_cpu(freqs.cpu) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + put_online_cpus(); + + return ret; +} + +static unsigned int omap_thermal_lower_speed(void) +{ + unsigned int max = 0; + unsigned int curr; + int i; + + curr = max_thermal; + + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) + if (freq_table[i].frequency > max && + freq_table[i].frequency < curr) + max = freq_table[i].frequency; + + if (!max) + return curr; + + return max; +} + +void omap_thermal_throttle(void) +{ + unsigned int cur; + + if (!omap_cpufreq_ready) { + pr_warn_once("%s: Thermal throttle prior to CPUFREQ ready\n", + __func__); + return; + } + + mutex_lock(&omap_cpufreq_lock); + + max_thermal = omap_thermal_lower_speed(); + + pr_warn("%s: temperature too high, cpu throttle at max %u\n", + __func__, max_thermal); + + if (!omap_cpufreq_suspended) { + cur = omap_getspeed(0); + if (cur > max_thermal) + omap_cpufreq_scale(max_thermal, cur); + } + + mutex_unlock(&omap_cpufreq_lock); +} + +void omap_thermal_unthrottle(void) +{ + unsigned int cur; + + if (!omap_cpufreq_ready) + return; + + mutex_lock(&omap_cpufreq_lock); + + if (max_thermal == max_freq) { + pr_warn("%s: not throttling\n", __func__); + goto out; + } + + max_thermal = max_freq; + + pr_warn("%s: temperature reduced, ending cpu throttling\n", __func__); + + if (!omap_cpufreq_suspended) { + cur = omap_getspeed(0); + omap_cpufreq_scale(current_target_freq, cur); + } + +out: + mutex_unlock(&omap_cpufreq_lock); +} + +static int omap_verify_speed(struct cpufreq_policy *policy) +{ + if (!freq_table) + return -EINVAL; + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static int omap_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int i; + int ret = 0; + + if (!freq_table) { + dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, + policy->cpu); + return -EINVAL; + } + + ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, + relation, &i); + if (ret) { + dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n", + __func__, policy->cpu, target_freq, ret); + return ret; + } + + mutex_lock(&omap_cpufreq_lock); + + current_target_freq = freq_table[i].frequency; + + if (!omap_cpufreq_suspended) + ret = omap_cpufreq_scale(current_target_freq, policy->cur); + + + mutex_unlock(&omap_cpufreq_lock); + + return ret; +} + +static inline void freq_table_free(void) +{ + if (atomic_dec_and_test(&freq_table_users)) + opp_free_cpufreq_table(mpu_dev, &freq_table); +} + +static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) +{ + int result = 0; + int i; + + mpu_clk = clk_get(NULL, mpu_clk_name); + if (IS_ERR(mpu_clk)) + return PTR_ERR(mpu_clk); + + if (policy->cpu >= NR_CPUS) { + result = -EINVAL; + goto fail_ck; + } + + policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu); + + if (atomic_inc_return(&freq_table_users) == 1) + result = opp_init_cpufreq_table(mpu_dev, &freq_table); + + if (result) { + dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n", + __func__, policy->cpu, result); + goto fail_ck; + } + + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (result) + goto fail_table; + + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + policy->cur = omap_getspeed(policy->cpu); + + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) + max_freq = max(freq_table[i].frequency, max_freq); + max_thermal = max_freq; + + /* + * On OMAP SMP configuartion, both processors share the voltage + * and clock. So both CPUs needs to be scaled together and hence + * needs software co-ordination. Use cpufreq affected_cpus + * interface to handle this scenario. Additional is_smp() check + * is to keep SMP_ON_UP build working. + */ + if (is_smp()) { + policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; + cpumask_setall(policy->cpus); + } + + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 300 * 1000; + + return 0; + +fail_table: + freq_table_free(); +fail_ck: + clk_put(mpu_clk); + return result; +} + +static int omap_cpu_exit(struct cpufreq_policy *policy) +{ + freq_table_free(); + clk_put(mpu_clk); + return 0; +} + +static struct freq_attr *omap_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver omap_driver = { + .flags = CPUFREQ_STICKY, + .verify = omap_verify_speed, + .target = omap_target, + .get = omap_getspeed, + .init = omap_cpu_init, + .exit = omap_cpu_exit, + .name = "omap2plus", + .attr = omap_cpufreq_attr, +}; + +static int omap_cpufreq_suspend_noirq(struct device *dev) +{ + mutex_lock(&omap_cpufreq_lock); + omap_cpufreq_suspended = true; + mutex_unlock(&omap_cpufreq_lock); + return 0; +} + +static int omap_cpufreq_resume_noirq(struct device *dev) +{ + unsigned int cur; + + mutex_lock(&omap_cpufreq_lock); + cur = omap_getspeed(0); + if (cur != current_target_freq) + omap_cpufreq_scale(current_target_freq, cur); + + omap_cpufreq_suspended = false; + mutex_unlock(&omap_cpufreq_lock); + return 0; +} + +static struct dev_pm_ops omap_cpufreq_driver_pm_ops = { + .suspend_noirq = omap_cpufreq_suspend_noirq, + .resume_noirq = omap_cpufreq_resume_noirq, +}; + +static struct platform_driver omap_cpufreq_platform_driver = { + .driver.name = "omap_cpufreq", + .driver.pm = &omap_cpufreq_driver_pm_ops, +}; +static struct platform_device omap_cpufreq_device = { + .name = "omap_cpufreq", +}; + +static int __init omap_cpufreq_init(void) +{ + int ret; + + if (cpu_is_omap24xx()) + mpu_clk_name = "virt_prcm_set"; + else if (cpu_is_omap34xx()) + mpu_clk_name = "dpll1_ck"; + else if (cpu_is_omap443x()) + mpu_clk_name = "dpll_mpu_ck"; + else if (cpu_is_omap446x()) + mpu_clk_name = "virt_dpll_mpu_ck"; + + if (!mpu_clk_name) { + pr_err("%s: unsupported Silicon?\n", __func__); + return -EINVAL; + } + + mpu_dev = omap2_get_mpuss_device(); + if (!mpu_dev) { + pr_warning("%s: unable to get the mpu device\n", __func__); + return -EINVAL; + } + + ret = cpufreq_register_driver(&omap_driver); + omap_cpufreq_ready = !ret; + + if (!ret) { + int t; + + t = platform_device_register(&omap_cpufreq_device); + if (t) + pr_warn("%s_init: platform_device_register failed\n", + __func__); + t = platform_driver_register(&omap_cpufreq_platform_driver); + if (t) + pr_warn("%s_init: platform_driver_register failed\n", + __func__); + } + + return ret; +} + +static void __exit omap_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&omap_driver); + platform_driver_unregister(&omap_cpufreq_platform_driver); + platform_device_unregister(&omap_cpufreq_device); +} + +MODULE_DESCRIPTION("cpufreq driver for OMAP2PLUS SOCs"); +MODULE_LICENSE("GPL"); +late_initcall(omap_cpufreq_init); +module_exit(omap_cpufreq_exit); diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 9ef8c29..7bf033c 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -14,38 +14,132 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/dma-mapping.h> #include <asm/hardware/gic.h> #include <asm/hardware/cache-l2x0.h> +#include <asm/cacheflush.h> +#include <asm/smp_twd.h> #include <mach/hardware.h> #include <mach/omap4-common.h> +#include <mach/omap-wakeupgen.h> + +#include "omap4-sar-layout.h" +#include "clockdomain.h" #ifdef CONFIG_CACHE_L2X0 -void __iomem *l2cache_base; +#define L2X0_POR_OFFSET_VALUE 0x7 +static void __iomem *l2cache_base; #endif -void __iomem *gic_dist_base_addr; +static void __iomem *gic_dist_base_addr; +static void __iomem *gic_cpu_base; +static struct clockdomain *l4_secure_clkdm; +static void *dram_barrier_base; + +static void omap_bus_sync_noop(void) +{ } + +struct omap_bus_post_fns omap_bus_post = { + .sync = omap_bus_sync_noop, +}; +EXPORT_SYMBOL(omap_bus_post); + +void __iomem *omap4_get_gic_dist_base(void) +{ + return gic_dist_base_addr; +} +void __iomem *omap4_get_gic_cpu_base(void) +{ + return gic_cpu_base; +} + +void *omap_get_dram_barrier_base(void) +{ + return dram_barrier_base; +} void __init gic_init_irq(void) { - void __iomem *gic_cpu_base; /* Static mapping, never released */ gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K); - BUG_ON(!gic_dist_base_addr); + if (WARN_ON(!gic_dist_base_addr)) + return; /* Static mapping, never released */ gic_cpu_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512); - BUG_ON(!gic_cpu_base); + if (WARN_ON(!gic_cpu_base)) + return; + + omap_wakeupgen_init(); gic_init(0, 29, gic_dist_base_addr, gic_cpu_base); } +/* + * FIXME: Remove this GIC APIs once common GIG library starts + * supporting it. + */ +void gic_cpu_enable(void) +{ + __raw_writel(0xf0, gic_cpu_base + GIC_CPU_PRIMASK); + __raw_writel(1, gic_cpu_base + GIC_CPU_CTRL); +} + +void gic_cpu_disable(void) +{ + __raw_writel(0, gic_cpu_base + GIC_CPU_CTRL); +} + + +bool gic_dist_disabled(void) +{ + return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1); +} + +void gic_dist_enable(void) +{ + if (cpu_is_omap443x() || gic_dist_disabled()) + __raw_writel(0x1, gic_dist_base_addr + GIC_DIST_CTRL); +} +void gic_dist_disable(void) +{ + __raw_writel(0, gic_dist_base_addr + GIC_CPU_CTRL); +} + +void gic_timer_retrigger(void) +{ + u32 twd_int = __raw_readl(twd_base + TWD_TIMER_INTSTAT); + u32 gic_int = __raw_readl(gic_dist_base_addr + GIC_DIST_PENDING_SET); + u32 twd_ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL); + + if (twd_int && !(gic_int & BIT(OMAP44XX_IRQ_LOCALTIMER))) { + /* + * The local timer interrupt got lost while the distributor was + * disabled. Ack the pending interrupt, and retrigger it. + */ + pr_warn("%s: lost localtimer interrupt\n", __func__); + __raw_writel(1, twd_base + TWD_TIMER_INTSTAT); + if (!(twd_ctrl & TWD_TIMER_CONTROL_PERIODIC)) { + __raw_writel(1, twd_base + TWD_TIMER_COUNTER); + twd_ctrl |= TWD_TIMER_CONTROL_ENABLE; + __raw_writel(twd_ctrl, twd_base + TWD_TIMER_CONTROL); + } + } +} + #ifdef CONFIG_CACHE_L2X0 +void __iomem *omap4_get_l2cache_base(void) +{ + return l2cache_base; +} + static void omap4_l2x0_disable(void) { /* Disable PL310 L2 Cache controller */ @@ -61,6 +155,9 @@ static void omap4_l2x0_set_debug(unsigned long val) static int __init omap_l2_cache_init(void) { u32 aux_ctrl = 0; + u32 por_ctrl = 0; + u32 lockdown = 0; + bool mpu_prefetch_disable_errata = false; /* * To avoid code running on other OMAPs in @@ -69,32 +166,77 @@ static int __init omap_l2_cache_init(void) if (!cpu_is_omap44xx()) return -ENODEV; +#ifdef CONFIG_OMAP_ALLOW_OSWR + if (omap_rev() == OMAP4460_REV_ES1_0) + mpu_prefetch_disable_errata = true; +#endif + /* Static mapping, never released */ l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K); - BUG_ON(!l2cache_base); + if (WARN_ON(!l2cache_base)) + return -ENODEV; /* * 16-way associativity, parity disabled * Way size - 32KB (es1.0) * Way size - 64KB (es2.0 +) */ - aux_ctrl = ((1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) | - (0x1 << 25) | - (0x1 << L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT) | - (0x1 << L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT)); + aux_ctrl = readl_relaxed(l2cache_base + L2X0_AUX_CTRL); if (omap_rev() == OMAP4430_REV_ES1_0) { aux_ctrl |= 0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT; - } else { - aux_ctrl |= ((0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | - (1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | - (1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | - (1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) | - (1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT)); + goto skip_aux_por_api; } - if (omap_rev() != OMAP4430_REV_ES1_0) - omap_smc1(0x109, aux_ctrl); + /* + * Drop instruction prefetch hint since it degrades the + * the performance. + */ + aux_ctrl |= ((0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | + (1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | + (1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT)); + + if (!mpu_prefetch_disable_errata) + aux_ctrl |= (1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT); + + omap_smc1(0x109, aux_ctrl); + + /* Setup POR Control register */ + por_ctrl = readl_relaxed(l2cache_base + L2X0_PREFETCH_CTRL); + + /* + * Double linefill is available only on OMAP4460 L2X0. + * It may cause single cache line memory corruption, leave it disabled + * on all devices + */ + por_ctrl &= ~(1 << L2X0_PREFETCH_DOUBLE_LINEFILL_SHIFT); + if (!mpu_prefetch_disable_errata) { + por_ctrl |= 1 << L2X0_PREFETCH_DATA_PREFETCH_SHIFT; + por_ctrl |= L2X0_POR_OFFSET_VALUE; + } + + /* Set POR through PPA service only in EMU/HS devices */ + if (omap_type() != OMAP2_DEVICE_TYPE_GP) + omap4_secure_dispatcher(PPA_SERVICE_PL310_POR, 0x7, 1, + por_ctrl, 0, 0, 0); + else if (omap_rev() >= OMAP4430_REV_ES2_1) + omap_smc1(0x113, por_ctrl); + + + /* + * FIXME: Temporary WA for OMAP4460 stability issue. + * Lock-down specific L2 cache ways which makes effective + * L2 size as 512 KB instead of 1 MB + */ + if (omap_rev() == OMAP4460_REV_ES1_0) { + lockdown = 0xa5a5; + writel_relaxed(lockdown, l2cache_base + L2X0_LOCKDOWN_WAY_D0); + writel_relaxed(lockdown, l2cache_base + L2X0_LOCKDOWN_WAY_D1); + writel_relaxed(lockdown, l2cache_base + L2X0_LOCKDOWN_WAY_I0); + writel_relaxed(lockdown, l2cache_base + L2X0_LOCKDOWN_WAY_I1); + } + +skip_aux_por_api: /* Enable PL310 L2 Cache controller */ omap_smc1(0x102, 0x1); @@ -111,3 +253,74 @@ static int __init omap_l2_cache_init(void) } early_initcall(omap_l2_cache_init); #endif + +static int __init omap_barriers_init(void) +{ + dma_addr_t dram_phys; + + if (!cpu_is_omap44xx()) + return -ENODEV; + + dram_barrier_base = dma_alloc_stronglyordered(NULL, SZ_4K, + (dma_addr_t *)&dram_phys, GFP_KERNEL); + if (!dram_barrier_base) { + pr_err("%s: failed to allocate memory.\n", __func__); + return -ENOMEM; + } + + omap_bus_post.sync = omap_bus_sync; + + return 0; +} +core_initcall(omap_barriers_init); + +/* + * omap4_sec_dispatcher: Routine to dispatch low power secure + * service routines + * + * @idx: The HAL API index + * @flag: The flag indicating criticality of operation + * @nargs: Number of valid arguments out of four. + * @arg1, arg2, arg3 args4: Parameters passed to secure API + * + * Return the error value on success/failure + */ +u32 omap4_secure_dispatcher(u32 idx, u32 flag, u32 nargs, u32 arg1, u32 arg2, + u32 arg3, u32 arg4) +{ + u32 ret; + u32 param[5]; + + param[0] = nargs; + param[1] = arg1; + param[2] = arg2; + param[3] = arg3; + param[4] = arg4; + + /* Look-up Only once */ + if (!l4_secure_clkdm) + l4_secure_clkdm = clkdm_lookup("l4_secure_clkdm"); + + /* + * Put l4 secure to software wakeup so that secure + * modules are accessible + */ + clkdm_wakeup(l4_secure_clkdm); + + /* + * Secure API needs physical address + * pointer for the parameters + */ + flush_cache_all(); + outer_clean_range(__pa(param), __pa(param + 5)); + + ret = omap_smc2(idx, flag, __pa(param)); + + /* + * Restore l4 secure to hardware superwised to allow + * secure modules idle + */ + clkdm_allow_idle(l4_secure_clkdm); + + return ret; +} diff --git a/arch/arm/mach-omap2/omap4-mpuss-lowpower.c b/arch/arm/mach-omap2/omap4-mpuss-lowpower.c new file mode 100644 index 0000000..81511e8 --- /dev/null +++ b/arch/arm/mach-omap2/omap4-mpuss-lowpower.c @@ -0,0 +1,824 @@ +/* + * OMAP4 MPUSS low power code + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Written by Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * OMAP4430 MPUSS mainly consists of dual Cortex-A9 with per-CPU + * Local timer and Watchdog, GIC, SCU, PL310 L2 cache controller, + * CPU0 and CPU1 LPRM modules. + * CPU0, CPU1 and MPUSS each have there own power domain and + * hence multiple low power combinations of MPUSS are possible. + * + * The CPU0 and CPU1 can't support Closed switch Retention (CSWR) + * because the mode is not supported by hw constraints of dormant + * mode. While waking up from the dormant mode, a reset signal + * to the Cortex-A9 processor must be asserted by the external + * power controller. + * + * With architectural inputs and hardware recommendations, only + * below modes are supported from power gain vs latency point of view. + * + * CPU0 CPU1 MPUSS + * ---------------------------------------------- + * ON ON ON + * ON(Inactive) OFF ON(Inactive) + * OFF OFF CSWR + * OFF OFF OSWR + * OFF OFF OFF + * ---------------------------------------------- + * + * Note: CPU0 is the master core and it is the last CPU to go down + * and first to wake-up when MPUSS low power states are excercised + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/errno.h> +#include <linux/linkage.h> +#include <linux/smp.h> + +#include <asm/cacheflush.h> +#include <linux/dma-mapping.h> + +#include <asm/tlbflush.h> +#include <asm/smp_scu.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/hardware/gic.h> +#include <asm/hardware/cache-l2x0.h> + +#include <plat/omap44xx.h> +#include <mach/omap4-common.h> +#include <mach/omap-wakeupgen.h> + +#include "omap4-sar-layout.h" +#include "pm.h" +#include "prcm_mpu44xx.h" +#include "prminst44xx.h" +#include "prcm44xx.h" +#include "prm44xx.h" +#include "prm-regbits-44xx.h" +#include "cm.h" +#include "prm.h" +#include "cm44xx.h" +#include "prcm-common.h" + +#ifdef CONFIG_SMP + +#define GIC_MASK_ALL 0x0 +#define GIC_ISR_NON_SECURE 0xffffffff +#define SPI_ENABLE_SET_OFFSET 0x04 +#define PPI_PRI_OFFSET 0x1c +#define SPI_PRI_OFFSET 0x20 +#define SPI_TARGET_OFFSET 0x20 +#define SPI_CONFIG_OFFSET 0x20 + +/* GIC save SAR bank base */ +static struct powerdomain *mpuss_pd; +/* + * Maximum Secure memory storage size. + */ +#define OMAP4_SECURE_RAM_STORAGE (88 * SZ_1K) +/* + * Physical address of secure memory storage + */ +dma_addr_t omap4_secure_ram_phys; +static void *secure_ram; + +/* Variables to store maximum spi(Shared Peripheral Interrupts) registers. */ +static u32 max_spi_irq, max_spi_reg; + +struct omap4_cpu_pm_info { + struct powerdomain *pwrdm; + void __iomem *scu_sar_addr; +}; + +static void __iomem *gic_dist_base; +static void __iomem *gic_cpu_base; +static void __iomem *sar_base; + +static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); + +#define PPI_CONTEXT_SIZE 11 +static DEFINE_PER_CPU(u32[PPI_CONTEXT_SIZE], gic_ppi_context); +static DEFINE_PER_CPU(u32, gic_ppi_enable_mask); + +/* Helper functions */ +static inline void sar_writel(u32 val, u32 offset, u8 idx) +{ + __raw_writel(val, sar_base + offset + 4 * idx); +} + +static inline u32 gic_readl(u32 offset, u8 idx) +{ + return __raw_readl(gic_dist_base + offset + 4 * idx); +} + +u32 gic_cpu_read(u32 reg) +{ + return __raw_readl(gic_cpu_base + reg); +} + +/* + * Set the CPUx powerdomain's previous power state + */ +static inline void set_cpu_next_pwrst(unsigned int cpu_id, + unsigned int power_state) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); +} + +/* + * Read CPU's previous power state + */ +static inline unsigned int read_cpu_prev_pwrst(unsigned int cpu_id) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + return pwrdm_read_prev_pwrst(pm_info->pwrdm); +} + +/* + * Clear the CPUx powerdomain's previous power state + */ +static inline void clear_cpu_prev_pwrst(unsigned int cpu_id) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); +} + +struct reg_tuple { + void __iomem *addr; + u32 val; +}; + +static struct reg_tuple tesla_reg[] = { + {.addr = OMAP4430_CM_TESLA_CLKSTCTRL}, + {.addr = OMAP4430_CM_TESLA_TESLA_CLKCTRL}, + {.addr = OMAP4430_PM_TESLA_PWRSTCTRL}, +}; + +static struct reg_tuple ivahd_reg[] = { + {.addr = OMAP4430_CM_IVAHD_CLKSTCTRL}, + {.addr = OMAP4430_CM_IVAHD_IVAHD_CLKCTRL}, + {.addr = OMAP4430_CM_IVAHD_SL2_CLKCTRL}, + {.addr = OMAP4430_PM_IVAHD_PWRSTCTRL} +}; + +static struct reg_tuple l3instr_reg[] = { + {.addr = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL}, + {.addr = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL}, + {.addr = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL}, +}; + +/* + * Store the SCU power status value to scratchpad memory + */ +static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + u32 scu_pwr_st; + + switch (cpu_state) { + case PWRDM_POWER_RET: + scu_pwr_st = SCU_PM_DORMANT; + break; + case PWRDM_POWER_OFF: + scu_pwr_st = SCU_PM_POWEROFF; + break; + case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: + default: + scu_pwr_st = SCU_PM_NORMAL; + break; + } + + __raw_writel(scu_pwr_st, pm_info->scu_sar_addr); +} + +static void gic_save_ppi(void) +{ + void __iomem *gic_dist_base = omap4_get_gic_dist_base(); + u32 *context = __get_cpu_var(gic_ppi_context); + int i = 0; + + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x4); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x8); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0xc); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x10); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x14); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x18); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x1c); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_CONFIG); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_CONFIG + 0x4); + context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_ENABLE_SET); + + BUG_ON(i != PPI_CONTEXT_SIZE); +} + +static void gic_restore_ppi(void) +{ + void __iomem *gic_dist_base = omap4_get_gic_dist_base(); + u32 *context = __get_cpu_var(gic_ppi_context); + int i = 0; + + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x4); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x8); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0xc); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x10); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x14); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x18); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x1c); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_CONFIG); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_CONFIG + 0x4); + writel_relaxed(context[i++], gic_dist_base + GIC_DIST_ENABLE_SET); + + BUG_ON(i != PPI_CONTEXT_SIZE); +} + +/* + * Mask all the PPIs. This should only be called after they have been saved + * through secure trap or through save_ppi(). This is primarily needed to + * mask the local timer irq that could be pending since timekeeping gets + * suspended after the local irqs are disabled. The pending interrupt would + * kick the CPU out of WFI immediately, and prevent it from going to the lower + * power states. The correct value will be restored when the CPU is brought + * back up by restore. + */ +static void gic_mask_ppi(void) +{ + void __iomem *gic_dist_base = omap4_get_gic_dist_base(); + + __get_cpu_var(gic_ppi_enable_mask) = + readl_relaxed(gic_dist_base + GIC_DIST_ENABLE_SET); + writel_relaxed(0xffffffff, gic_dist_base + GIC_DIST_ENABLE_CLEAR); +} + +static void gic_unmask_ppi(void) +{ + void __iomem *gic_dist_base = omap4_get_gic_dist_base(); + writel_relaxed(__get_cpu_var(gic_ppi_enable_mask), + gic_dist_base + GIC_DIST_ENABLE_SET); +} + +/* + * Save GIC context in SAR RAM. Restore is done by ROM code + * GIC is lost only when MPU hits OSWR or OFF. It consists + * of a distributor and a per-CPU interface module. The GIC + * save restore is optimised to save only necessary registers. + */ +static void gic_save_context(void) +{ + u8 i; + u32 val; + + /* + * Interrupt Clear Enable registers are inverse of set enable + * and hence not needed to be saved. ROM code programs it + * based on Set Enable register values. + */ + + /* Save CPU 0 Interrupt Set Enable register */ + val = gic_readl(GIC_DIST_ENABLE_SET, 0); + sar_writel(val, ICDISER_CPU0_OFFSET, 0); + + /* Disable interrupts on CPU1 */ + sar_writel(GIC_MASK_ALL, ICDISER_CPU1_OFFSET, 0); + + /* Save all SPI Set Enable register */ + for (i = 0; i < max_spi_reg; i++) { + val = gic_readl(GIC_DIST_ENABLE_SET + SPI_ENABLE_SET_OFFSET, i); + sar_writel(val, ICDISER_SPI_OFFSET, i); + } + + /* + * Interrupt Priority Registers + * Secure sw accesses, last 5 bits of the 8 bits (bit[7:3] are used) + * Non-Secure sw accesses, last 4 bits (i.e. bits[7:4] are used) + * But the Secure Bits[7:3] are shifted by 1 in Non-Secure access. + * Secure (bits[7:3] << 1)== Non Secure bits[7:4] + * Hence right shift the value by 1 while saving the priority + */ + + /* Save SGI priority registers (Software Generated Interrupt) */ + for (i = 0; i < 4; i++) { + val = gic_readl(GIC_DIST_PRI, i); + + /* Save the priority bits of the Interrupts */ + sar_writel(val >> 0x1, ICDIPR_SFI_CPU0_OFFSET, i); + + /* Disable the interrupts on CPU1 */ + sar_writel(GIC_MASK_ALL, ICDIPR_SFI_CPU1_OFFSET, i); + } + + /* Save PPI priority registers (Private Peripheral Intterupts) */ + val = gic_readl(GIC_DIST_PRI + PPI_PRI_OFFSET, 0); + sar_writel(val >> 0x1, ICDIPR_PPI_CPU0_OFFSET, 0); + sar_writel(GIC_MASK_ALL, ICDIPR_PPI_CPU1_OFFSET, 0); + + /* SPI priority registers - 4 interrupts/register */ + for (i = 0; i < (max_spi_irq / 4); i++) { + val = gic_readl((GIC_DIST_PRI + SPI_PRI_OFFSET), i); + sar_writel(val >> 0x1, ICDIPR_SPI_OFFSET, i); + } + + /* SPI Interrupt Target registers - 4 interrupts/register */ + for (i = 0; i < (max_spi_irq / 4); i++) { + val = gic_readl((GIC_DIST_TARGET + SPI_TARGET_OFFSET), i); + sar_writel(val, ICDIPTR_SPI_OFFSET, i); + } + + /* SPI Interrupt Congigeration eegisters- 16 interrupts/register */ + for (i = 0; i < (max_spi_irq / 16); i++) { + val = gic_readl((GIC_DIST_CONFIG + SPI_CONFIG_OFFSET), i); + sar_writel(val, ICDICFR_OFFSET, i); + } + + /* Set the Backup Bit Mask status for GIC */ + val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET); + val |= (SAR_BACKUP_STATUS_GIC_CPU0 | SAR_BACKUP_STATUS_GIC_CPU1); + __raw_writel(val, sar_base + SAR_BACKUP_STATUS_OFFSET); +} +/* + * API to save GIC and Wakeupgen using secure API + * for HS/EMU device + */ +static void save_gic_wakeupgen_secure(void) +{ + u32 ret; + ret = omap4_secure_dispatcher(HAL_SAVEGIC_INDEX, + FLAG_START_CRITICAL, + 0, 0, 0, 0, 0); + if (!ret) + pr_debug("GIC and Wakeupgen context save failed\n"); +} + + +/* + * API to save Secure RAM, GIC, WakeupGen Registers using secure API + * for HS/EMU device + */ +static void save_secure_all(void) +{ + u32 ret; + ret = omap4_secure_dispatcher(HAL_SAVEALL_INDEX, + FLAG_START_CRITICAL, + 1, omap4_secure_ram_phys, 0, 0, 0); + if (ret) + pr_debug("Secure all context save failed\n"); +} + +/* + * API to save Secure RAM using secure API + * for HS/EMU device + */ +static void save_secure_ram(void) +{ + u32 ret; + ret = omap4_secure_dispatcher(HAL_SAVESECURERAM_INDEX, + FLAG_START_CRITICAL, + 1, omap4_secure_ram_phys, 0, 0, 0); + if (!ret) + pr_debug("Secure ram context save failed\n"); +} + +/* Helper functions for MPUSS OSWR */ +static inline u32 mpuss_read_prev_logic_pwrst(void) +{ + u32 reg; + + reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); + reg &= OMAP4430_LOSTCONTEXT_DFF_MASK; + return reg; +} + +static inline void mpuss_clear_prev_logic_pwrst(void) +{ + u32 reg; + + reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); + omap4_prminst_write_inst_reg(reg, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); +} + +static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id) +{ + u32 reg; + + if (cpu_id) { + reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU1_INST, + OMAP4_RM_CPU1_CPU1_CONTEXT_OFFSET); + omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU1_INST, + OMAP4_RM_CPU1_CPU1_CONTEXT_OFFSET); + } else { + reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU0_INST, + OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET); + omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU0_INST, + OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET); + } +} + +static inline void save_ivahd_tesla_regs(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tesla_reg); i++) + tesla_reg[i].val = __raw_readl(tesla_reg[i].addr); + + for (i = 0; i < ARRAY_SIZE(ivahd_reg); i++) + ivahd_reg[i].val = __raw_readl(ivahd_reg[i].addr); +} + +static inline void restore_ivahd_tesla_regs(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tesla_reg); i++) + __raw_writel(tesla_reg[i].val, tesla_reg[i].addr); + + for (i = 0; i < ARRAY_SIZE(ivahd_reg); i++) + __raw_writel(ivahd_reg[i].val, ivahd_reg[i].addr); +} + +static inline void save_l3instr_regs(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(l3instr_reg); i++) + l3instr_reg[i].val = __raw_readl(l3instr_reg[i].addr); +} + +static inline void restore_l3instr_regs(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(l3instr_reg); i++) + __raw_writel(l3instr_reg[i].val, l3instr_reg[i].addr); +} + +/* + * OMAP4 MPUSS Low Power Entry Function + * + * The purpose of this function is to manage low power programming + * of OMAP4 MPUSS subsystem + * Paramenters: + * cpu : CPU ID + * power_state: Targetted Low power state. + * + * MPUSS Low power states + * The basic rule is that the MPUSS power domain must be at the higher or + * equal power state (state that consume more power) than the higher of the + * two CPUs. For example, it is illegal for system power to be OFF, while + * the power of one or both of the CPU is DORMANT. When an illegal state is + * entered, then the hardware behavior is unpredictable. + * + * MPUSS state for the context save + * save_state = + * 0 - Nothing lost and no need to save: MPUSS INACTIVE + * 1 - CPUx L1 and logic lost: MPUSS CSWR + * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR + * 3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF + */ +int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) +{ + unsigned int save_state = 0; + unsigned int wakeup_cpu; + + if ((cpu >= NR_CPUS) || (omap_rev() == OMAP4430_REV_ES1_0)) + goto ret; + + switch (power_state) { + case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: + save_state = 0; + break; + case PWRDM_POWER_OFF: + save_state = 1; + break; + case PWRDM_POWER_RET: + default: + /* + * CPUx CSWR is invalid hardware state. Also CPUx OSWR + * doesn't make much scense, since logic is lost and $L1 + * needs to be cleaned because of coherency. This makes + * CPUx OSWR equivalent to CPUX OFF and hence not supported + */ + WARN_ON(1); + goto ret; + } + + /* + * MPUSS book keeping should be executed by master + * CPU only which is also the last CPU to go down. + */ + if (cpu) + goto cpu_prepare; + + pwrdm_pre_transition(); + + /* + * Check MPUSS next state and save GIC if needed + * GIC lost during MPU OFF and OSWR + */ + pwrdm_clear_all_prev_pwrst(mpuss_pd); + mpuss_clear_prev_logic_pwrst(); + if (omap4_device_next_state_off()) { + if (omap_type() == OMAP2_DEVICE_TYPE_GP) { + omap_wakeupgen_save(); + gic_save_context(); + } else { + save_secure_all(); + save_ivahd_tesla_regs(); + save_l3instr_regs(); + } + save_state = 3; + goto cpu_prepare; + } + + switch (pwrdm_read_next_pwrst(mpuss_pd)) { + case PWRDM_POWER_RET: + /* + * MPUSS OSWR - Complete logic lost + L2$ retained. + * MPUSS CSWR - Complete logic retained + L2$ retained. + */ + if (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF) { + if (omap_type() == OMAP2_DEVICE_TYPE_GP) { + omap_wakeupgen_save(); + gic_save_context(); + } else { + save_gic_wakeupgen_secure(); + save_ivahd_tesla_regs(); + save_l3instr_regs(); + } + save_state = 2; + } + break; + case PWRDM_POWER_OFF: + /* MPUSS OFF - logic lost + L2$ lost */ + if (omap_type() == OMAP2_DEVICE_TYPE_GP) { + omap_wakeupgen_save(); + gic_save_context(); + } else { + save_gic_wakeupgen_secure(); + save_ivahd_tesla_regs(); + save_l3instr_regs(); + save_secure_ram(); + } + save_state = 3; + break; + case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: + /* No need to save MPUSS context */ + default: + ; + } + +cpu_prepare: + if (cpu) + gic_save_ppi(); + + /* + * mask all PPIs to prevent them from kicking us out of wfi. + */ + gic_mask_ppi(); + + clear_cpu_prev_pwrst(cpu); + cpu_clear_prev_logic_pwrst(cpu); + set_cpu_next_pwrst(cpu, power_state); + scu_pwrst_prepare(cpu, power_state); + + /* + * Call low level function with targeted CPU id + * and its low power state. + */ + stop_critical_timings(); + omap4_cpu_suspend(cpu, save_state); + start_critical_timings(); + + /* + * Restore the CPUx power state to ON otherwise CPUx + * power domain can transitions to programmed low power + * state while doing WFI outside the low powe code. On + * secure devices, CPUx does WFI which can result in + * domain transition + */ + wakeup_cpu = hard_smp_processor_id(); + set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); + + /* + * If we didn't actually get into the low power state (e.g. immediately + * exited wfi due to a pending interrupt), the secure side + * would not have restored CPU0's GIC PPI enable mask. + * For other CPUs, gic_restore_ppi will do that for us. + */ + if (cpu) + gic_restore_ppi(); + else + gic_unmask_ppi(); + + /* + * If !master cpu return to hotplug-path. + * + * GIC distributor control register has changed between + * CortexA9 r1pX and r2pX. The Control Register secure + * banked version is now composed of 2 bits: + * bit 0 == Secure Enable + * bit 1 == Non-Secure Enable + * The Non-Secure banked register has not changed + * Because the ROM Code is based on the r1pX GIC, the CPU1 + * GIC restoration will cause a problem to CPU0 Non-Secure SW. + * The workaround must be: + * 1) Before doing the CPU1 wakeup, CPU0 must disable + * the GIC distributor + * 2) CPU1 must re-enable the GIC distributor on + * it's wakeup path. + */ + if (wakeup_cpu) { + if (!cpu_is_omap443x()) + gic_dist_enable(); + goto ret; + } + + /* Check if MPUSS lost it's logic */ + if (mpuss_read_prev_logic_pwrst()) { + /* Clear SAR BACKUP status on GP devices */ + if (omap_type() == OMAP2_DEVICE_TYPE_GP) + __raw_writel(0x0, sar_base + SAR_BACKUP_STATUS_OFFSET); + /* Enable GIC distributor and inteface on CPU0*/ + gic_cpu_enable(); + gic_dist_enable(); + + /* + * Dummy dispatcher call after OSWR and OFF + * Restore the right return Kernel address (with MMU on) for + * subsequent calls to secure ROM. Otherwise the return address + * will be to a PA return address and the system will hang. + */ + if (omap_type() != OMAP2_DEVICE_TYPE_GP) + omap4_secure_dispatcher(PPA_SERVICE_0, + FLAG_START_CRITICAL, + 0, 0, 0, 0, 0); + } + + if (omap4_device_prev_state_off()) { + restore_ivahd_tesla_regs(); + restore_l3instr_regs(); + } + + pwrdm_post_transition(); + +ret: + return 0; +} + +static void save_l2x0_auxctrl(void) +{ +#ifdef CONFIG_CACHE_L2X0 + /* + * Save the L2X0 AUXCTRL value to SAR memory. Its used to + * in every restore patch MPUSS OFF path. + */ + void __iomem *l2x0_base = omap4_get_l2cache_base(); + u32 val; + + val = __raw_readl(l2x0_base + L2X0_AUX_CTRL); + __raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET); + + /* + * Save the L2X0 PREFETCH_CTRL value to SAR memory. + * Its used in every restore path MPUSS OFF path. + */ + + val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL); + __raw_writel(val, sar_base + L2X0_PREFETCHCTRL_OFFSET); + + /* Save L2X0 LOCKDOWN_OFFSET0 during SAR */ + val = readl_relaxed(l2x0_base + 0x900); + writel_relaxed(val, sar_base + L2X0_LOCKDOWN_OFFSET0); +#endif +} + +/* + * Initialise OMAP4 MPUSS + */ +int __init omap4_mpuss_init(void) +{ + struct omap4_cpu_pm_info *pm_info; + u8 i; + + /* Get GIC and SAR RAM base addresses */ + sar_base = omap4_get_sar_ram_base(); + gic_dist_base = omap4_get_gic_dist_base(); + gic_cpu_base = omap4_get_gic_cpu_base(); + + if (omap_rev() == OMAP4430_REV_ES1_0) { + WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); + return -ENODEV; + } + + /* Initilaise per CPU PM information */ + pm_info = &per_cpu(omap4_pm_info, 0x0); + pm_info->scu_sar_addr = sar_base + SCU_OFFSET0; + pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm"); + if (!pm_info->pwrdm) { + pr_err("Lookup failed for CPU0 pwrdm\n"); + return -ENODEV; + } + + /* Clear CPU previous power domain state */ + pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); + cpu_clear_prev_logic_pwrst(0); + + /* Initialise CPU0 power domain state to ON */ + pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); + + pm_info = &per_cpu(omap4_pm_info, 0x1); + pm_info->scu_sar_addr = sar_base + SCU_OFFSET1; + pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm"); + if (!pm_info->pwrdm) { + pr_err("Lookup failed for CPU1 pwrdm\n"); + return -ENODEV; + } + + /* + * Check the OMAP type and store it to scratchpad + */ + if (omap_type() != OMAP2_DEVICE_TYPE_GP) { + /* Memory not released */ + secure_ram = dma_alloc_coherent(NULL, OMAP4_SECURE_RAM_STORAGE, + (dma_addr_t *)&omap4_secure_ram_phys, GFP_ATOMIC); + if (!secure_ram) + pr_err("Unable to allocate secure ram storage\n"); + writel(0x1, sar_base + OMAP_TYPE_OFFSET); + } else { + writel(0x0, sar_base + OMAP_TYPE_OFFSET); + } + + /* Clear CPU previous power domain state */ + pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); + cpu_clear_prev_logic_pwrst(1); + + /* Initialise CPU1 power domain state to ON */ + pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); + + /* + * Program the wakeup routine address for the CPU0 and CPU1 + * used for OFF or DORMANT wakeup. Wakeup routine address + * is fixed so programit in init itself. + */ + __raw_writel(virt_to_phys(omap4_cpu_resume), + sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET); + __raw_writel(virt_to_phys(omap4_cpu_resume), + sar_base + CPU0_WAKEUP_NS_PA_ADDR_OFFSET); + + mpuss_pd = pwrdm_lookup("mpu_pwrdm"); + if (!mpuss_pd) { + pr_err("Failed to get lookup for MPUSS pwrdm\n"); + return -ENODEV; + } + + /* Clear CPU previous power domain state */ + pwrdm_clear_all_prev_pwrst(mpuss_pd); + mpuss_clear_prev_logic_pwrst(); + + /* + * Find out how many interrupts are supported. + * OMAP4 supports max of 128 SPIs where as GIC can support + * up to 1020 interrupt sources. On OMAP4, maximum SPIs are + * fused in DIST_CTR bit-fields as 128. Hence the code is safe + * from reserved register writes since its well within 1020. + */ + max_spi_reg = __raw_readl(gic_dist_base + GIC_DIST_CTR) & 0x1f; + max_spi_irq = max_spi_reg * 32; + + /* + * Mark the PPI and SPI interrupts as non-secure. + * program the SAR locations for interrupt security registers to + * reflect the same. + */ + if (omap_type() == OMAP2_DEVICE_TYPE_GP) { + sar_writel(GIC_ISR_NON_SECURE, ICDISR_CPU0_OFFSET, 0); + sar_writel(GIC_ISR_NON_SECURE, ICDISR_CPU1_OFFSET, 0); + for (i = 0; i < max_spi_reg; i++) + sar_writel(GIC_ISR_NON_SECURE, ICDISR_SPI_OFFSET, i); + } + save_l2x0_auxctrl(); + + return 0; +} + +#endif + diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h new file mode 100644 index 0000000..851db59 --- /dev/null +++ b/arch/arm/mach-omap2/omap4-sar-layout.h @@ -0,0 +1,124 @@ +/* + * omap4-sar-layout.h: OMAP4 SAR RAM layout header file + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * 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. + */ +#ifndef OMAP_ARCH_OMAP4_SAR_LAYOUT_H +#define OMAP_ARCH_OMAP4_SAR_LAYOUT_H + +#include <mach/hardware.h> +#include <mach/omap4-common.h> +#include <mach/emif-44xx.h> +#include <mach/dmm-44xx.h> +#include <mach/ctrl_module_pad_core_44xx.h> + +#include "cm1_44xx.h" +#include "cm2_44xx.h" +#include "prcm-common.h" + +/* + * The SAR RAM is maintained during Device OFF mode. + * It is split into 4 banks with different privilege accesses + * + * --------------------------------------------------------------------- + * Access mode Bank Address Range + * --------------------------------------------------------------------- + * HS/GP : Public 1 0x4A32_6000 - 0x4A32_6FFF (4kB) + * HS/GP : Public, Secured + * if padconfaccdisable=1 2 0x4A32_7000 - 0x4A32_73FF (1kB) + * HS/EMU : Secured + * GP : Public 3 0x4A32_8000 - 0x4A32_87FF (2kB) + * HS/GP : + * Secure Priviledge, + * write once. 4 0x4A32_9000 - 0x4A32_93FF (1kB) + * --------------------------------------------------------------------- + * The SAR RAM save regiter layout is fixed since restore is done by hardware. + */ + +#define MODULE_ADDR_IDX 0 +#define MODULE_OFFSET_IDX 1 +#define MODULE_NB_REGS_IDX 2 +#define SAR_RAM_OFFSET_IDX 3 + +/* + * Module Index used to lookup VA using index + */ +#define MAX_SAR_MODULES 14 +#define EMIF1_INDEX 0 +#define EMIF2_INDEX 1 +#define DMM_INDEX 2 +#define CM1_INDEX 3 +#define CM2_INDEX 4 +#define C2C_INDEX 5 +#define CTRL_MODULE_PAD_CORE_INDEX 6 +#define L3_CLK1_INDEX 7 +#define L3_CLK2_INDEX 8 +#define L3_CLK3_INDEX 9 +#define USBTLL_INDEX 10 +#define UHH_INDEX 11 +#define L4CORE_INDEX 12 +#define L4PER_INDEX 13 + +/* + * SAR BANK offsets from base address OMAP44XX_SAR_RAM_BASE + */ +#define SAR_BANK1_OFFSET 0x0000 +#define SAR_BANK2_OFFSET 0x1000 +#define SAR_BANK3_OFFSET 0x2000 +#define SAR_BANK4_OFFSET 0x3000 + +/* Scratch pad memory offsets from SAR_BANK1 */ +#define CPU0_SAVE_OFFSET 0xb00 +#define CPU1_SAVE_OFFSET 0xc00 +#define MMU_OFFSET0 0xd00 +#define MMU_OFFSET1 0xd10 +#define SCU_OFFSET0 0xd20 +#define SCU_OFFSET1 0xd24 +#define L2X0_AUXCTRL_OFFSET 0xd28 +#define OMAP_TYPE_OFFSET 0xd2c +#define L2X0_LOCKDOWN_OFFSET0 0xd30 +#define L2X0_PREFETCHCTRL_OFFSET 0xd34 +#define L2X0_SAVE_OFFSET0 0xd38 +#define L2X0_SAVE_OFFSET1 0xd3c + +/* CPUx Wakeup Non-Secure Physical Address offsets in SAR_BANK3 */ +#define CPU0_WAKEUP_NS_PA_ADDR_OFFSET 0xa04 +#define CPU1_WAKEUP_NS_PA_ADDR_OFFSET 0xa08 + +/* GIC save restore offset from SAR_BANK3 */ +#define SAR_BACKUP_STATUS_OFFSET (SAR_BANK3_OFFSET + 0x500) +#define SAR_SECURE_RAM_SIZE_OFFSET (SAR_BANK3_OFFSET + 0x504) +#define SAR_SECRAM_SAVED_AT_OFFSET (SAR_BANK3_OFFSET + 0x508) +#define ICDISR_CPU0_OFFSET (SAR_BANK3_OFFSET + 0x50c) +#define ICDISR_CPU1_OFFSET (SAR_BANK3_OFFSET + 0x510) +#define ICDISR_SPI_OFFSET (SAR_BANK3_OFFSET + 0x514) +#define ICDISER_CPU0_OFFSET (SAR_BANK3_OFFSET + 0x524) +#define ICDISER_CPU1_OFFSET (SAR_BANK3_OFFSET + 0x528) +#define ICDISER_SPI_OFFSET (SAR_BANK3_OFFSET + 0x52c) +#define ICDIPR_SFI_CPU0_OFFSET (SAR_BANK3_OFFSET + 0x53c) +#define ICDIPR_PPI_CPU0_OFFSET (SAR_BANK3_OFFSET + 0x54c) +#define ICDIPR_SFI_CPU1_OFFSET (SAR_BANK3_OFFSET + 0x550) +#define ICDIPR_PPI_CPU1_OFFSET (SAR_BANK3_OFFSET + 0x560) +#define ICDIPR_SPI_OFFSET (SAR_BANK3_OFFSET + 0x564) +#define ICDIPTR_SPI_OFFSET (SAR_BANK3_OFFSET + 0x5e4) +#define ICDICFR_OFFSET (SAR_BANK3_OFFSET + 0x664) +#define SAR_BACKUP_STATUS_GIC_CPU0 0x1 +#define SAR_BACKUP_STATUS_GIC_CPU1 0x2 + +/* WakeUpGen save restore offset from OMAP44XX_SAR_RAM_BASE */ +#define WAKEUPGENENB_OFFSET_CPU0 (SAR_BANK3_OFFSET + 0x684) +#define WAKEUPGENENB_SECURE_OFFSET_CPU0 (SAR_BANK3_OFFSET + 0x694) +#define WAKEUPGENENB_OFFSET_CPU1 (SAR_BANK3_OFFSET + 0x6a4) +#define WAKEUPGENENB_SECURE_OFFSET_CPU1 (SAR_BANK3_OFFSET + 0x6b4) +#define AUXCOREBOOT0_OFFSET (SAR_BANK3_OFFSET + 0x6c4) +#define AUXCOREBOOT1_OFFSET (SAR_BANK3_OFFSET + 0x6c8) +#define PTMSYNCREQ_MASK_OFFSET (SAR_BANK3_OFFSET + 0x6cc) +#define PTMSYNCREQ_EN_OFFSET (SAR_BANK3_OFFSET + 0x6d0) +#define SAR_BACKUP_STATUS_WAKEUPGEN 0x10 + +#endif diff --git a/arch/arm/mach-omap2/omap4-sar.c b/arch/arm/mach-omap2/omap4-sar.c new file mode 100644 index 0000000..85b5fe9 --- /dev/null +++ b/arch/arm/mach-omap2/omap4-sar.c @@ -0,0 +1,1054 @@ +/* + * OMAP4 Save Restore source file + * + * Copyright (C) 2010 Texas Instruments, Inc. + * Written by Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> + +#include <mach/omap4-common.h> +#include <mach/ctrl_module_wkup_44xx.h> + +#include "clockdomain.h" +#include "omap4-sar-layout.h" +#include "cm-regbits-44xx.h" +#include "prcm44xx.h" +#include "cminst44xx.h" + +/* + * These SECURE control registers are used to work-around + * DDR corruption on the second chip select on OMAP443x. + */ +#define OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG 0x0114 +#define OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG 0x011c + +static void __iomem *sar_ram_base; +static void __iomem *omap4_sar_modules[MAX_SAR_MODULES]; +static struct powerdomain *l3init_pwrdm; + static struct clockdomain *l3init_clkdm; +static struct clk *usb_host_ck, *usb_tll_ck; + +/* + * SAR_RAM1 register layout consist of EMIF1, EMIF2, CM1, CM2, + * CONTROL_CORE efuse, DMM and USB TLL registers. + * The layout is arranged is a two dimentional array like + * below, + * const u32 sar_ramX_layout[nb_regs_sets][4] = { + * {module_index, reg_offset, size, sar_ram_offset}, + * } + */ +static const u32 omap443x_sar_ram1_layout[][4] = { + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_CONFIG, 1, 0x00000000}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_CONFIG_2, 1, 0x00000004}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_REF_CTRL, 1, 0x00000008}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW, 1, 0x0000000C}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_1, 1, 0x00000010}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_1_SHDW, 1, 0x00000014}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_2, 1, 0x00000018}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_2_SHDW, 1, 0x0000001C}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_3, 1, 0x00000020}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_3_SHDW, 1, 0x00000024}, + {EMIF1_INDEX, OMAP44XX_EMIF_LPDDR2_NVM_TIM, 1, 0x00000028}, + {EMIF1_INDEX, OMAP44XX_EMIF_LPDDR2_NVM_TIM_SHDW, 1, 0x0000002C}, + {EMIF1_INDEX, OMAP44XX_EMIF_PWR_MGMT_CTRL, 1, 0x00000030}, + {EMIF1_INDEX, OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW, 1, 0x00000034}, + {EMIF1_INDEX, OMAP44XX_EMIF_OCP_CONFIG, 1, 0x00000038}, + {EMIF1_INDEX, OMAP44XX_EMIF_PERF_CNT_CFG, 1, 0x0000003C}, + {EMIF1_INDEX, OMAP44XX_EMIF_PERF_CNT_SEL, 1, 0x00000040}, + {EMIF1_INDEX, OMAP44XX_EMIF_READ_IDLE_CTRL, 1, 0x00000044}, + {EMIF1_INDEX, OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW, 1, 0x00000048}, + {EMIF1_INDEX, OMAP44XX_EMIF_IRQENABLE_SET_SYS, 1, 0x0000004C}, + {EMIF1_INDEX, OMAP44XX_EMIF_IRQENABLE_SET_LL, 1, 0x00000050}, + {EMIF1_INDEX, OMAP44XX_EMIF_ZQ_CONFIG, 1, 0x00000054}, + {EMIF1_INDEX, OMAP44XX_EMIF_TEMP_ALERT_CONFIG, 1, 0x00000058}, + {EMIF1_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_1, 1, 0x0000005C}, + {EMIF1_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW, 1, 0x00000060}, + {EMIF1_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_2, 1, 0x00000064}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_CONFIG, 1, 0x00000068}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_CONFIG_2, 1, 0x0000006C}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_REF_CTRL, 1, 0x00000070}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW, 1, 0x00000074}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_1, 1, 0x00000078}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_1_SHDW, 1, 0x0000007C}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_2, 1, 0x00000080}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_2_SHDW, 1, 0x00000084}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_3, 1, 0x00000088}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_3_SHDW, 1, 0x0000008C}, + {EMIF2_INDEX, OMAP44XX_EMIF_LPDDR2_NVM_TIM, 1, 0x00000090}, + {EMIF2_INDEX, OMAP44XX_EMIF_LPDDR2_NVM_TIM_SHDW, 1, 0x00000094}, + {EMIF2_INDEX, OMAP44XX_EMIF_PWR_MGMT_CTRL, 1, 0x00000098}, + {EMIF2_INDEX, OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW, 1, 0x0000009C}, + {EMIF2_INDEX, OMAP44XX_EMIF_OCP_CONFIG, 1, 0x000000A0}, + {EMIF2_INDEX, OMAP44XX_EMIF_PERF_CNT_CFG, 1, 0x000000A4}, + {EMIF2_INDEX, OMAP44XX_EMIF_PERF_CNT_SEL, 1, 0x000000A8}, + {EMIF2_INDEX, OMAP44XX_EMIF_READ_IDLE_CTRL, 1, 0x000000AC}, + {EMIF2_INDEX, OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW, 1, 0x000000B0}, + {EMIF2_INDEX, OMAP44XX_EMIF_IRQENABLE_SET_SYS, 1, 0x000000B4}, + {EMIF2_INDEX, OMAP44XX_EMIF_IRQENABLE_SET_LL, 1, 0x000000B8}, + {EMIF2_INDEX, OMAP44XX_EMIF_ZQ_CONFIG, 1, 0x000000BC}, + {EMIF2_INDEX, OMAP44XX_EMIF_TEMP_ALERT_CONFIG, 1, 0x000000C0}, + {EMIF2_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_1, 1, 0x000000C4}, + {EMIF2_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW, 1, 0x000000C8}, + {EMIF2_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_2, 1, 0x000000CC}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_MEMIF_CLKSTCTRL_RESTORE_OFFSET, 1, 0x000000D0}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_CLKSEL_CORE_RESTORE_OFFSET, 1, 0x000000D4}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M2_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000D8}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M3_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000DC}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M4_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000E0}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M5_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000E4}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M6_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000E8}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M7_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000EC}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_CLKSEL_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000F0}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000F4}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000F8}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_CLKMODE_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000FC}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_SHADOW_FREQ_CONFIG2_RESTORE_OFFSET, 1, 0x00000100}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_SHADOW_FREQ_CONFIG1_RESTORE_OFFSET, 1, 0x00000104}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_AUTOIDLE_DPLL_CORE_RESTORE_OFFSET, 1, 0x00000108}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_MPU_CLKSTCTRL_RESTORE_OFFSET, 1, 0x0000010C}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_CM1_PROFILING_CLKCTRL_RESTORE_OFFSET, 1, 0x00000110}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DYN_DEP_PRESCAL_RESTORE_OFFSET, 1, 0x00000114}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3_1_CLKSTCTRL_RESTORE_OFFSET, 1, 0x00000118}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3_2_CLKSTCTRL_RESTORE_OFFSET, 1, 0x0000011C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L4CFG_CLKSTCTRL_RESTORE_OFFSET, 1, 0x00000120}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_MEMIF_CLKSTCTRL_RESTORE_OFFSET, 1, 0x00000124}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L4PER_CLKSTCTRL_RESTORE_OFFSET, 1, 0x00000128}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_CLKSTCTRL_RESTORE_OFFSET, 1, 0x0000012C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INSTR_L3_3_CLKCTRL_RESTORE_OFFSET, 1, 0x00000130}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE_OFFSET, 1, 0x00000134}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE_OFFSET, 1, 0x00000138}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_CM2_PROFILING_CLKCTRL_RESTORE_OFFSET, 1, 0x0000013C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_D2D_STATICDEP_RESTORE_OFFSET, 1, 0x00000140}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3_1_DYNAMICDEP_RESTORE_OFFSET, 1, 0x00000144}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3_2_DYNAMICDEP_RESTORE_OFFSET, 1, 0x00000148}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_D2D_DYNAMICDEP_RESTORE_OFFSET, 1, 0x0000014C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L4CFG_DYNAMICDEP_RESTORE_OFFSET, 1, 0x00000150}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L4PER_DYNAMICDEP_RESTORE_OFFSET, 1, 0x00000154}, + {C2C_INDEX, 0x0C, 1, 0x00000158}, + {C2C_INDEX, 0x10, 1, 0x0000015C}, + {C2C_INDEX, 0x28, 1, 0x00000160}, + {C2C_INDEX, 0x40, 1, 0x00000164}, + {C2C_INDEX, 0x44, 1, 0x00000168}, + {C2C_INDEX, 0x70, 1, 0x0000016C}, + {C2C_INDEX, 0x74, 1, 0x00000170}, + {C2C_INDEX, 0x84, 1, 0x00000174}, + {C2C_INDEX, 0x88, 1, 0x00000178}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PADCONF_GLOBAL, 15, 0x0000017C}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE, 14, 0x000001B8}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_0, 8, 0x000001F0}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_BUS_HOLD, 1, 0x00000210}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_C2C, 1, 0x00000214}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_1, 1, 0x00000218}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_2, 1, 0x0000021C}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_4, 1, 0x00000220}, + {DMM_INDEX, OMAP44XX_DMM_LISA_MAP, 4, 0x000000224}, + {DMM_INDEX, OMAP44XX_DMM_LISA_LOCK, 1, 0x00000234}, + {DMM_INDEX, OMAP44XX_DMM_TILER_OR, 2, 0x00000238}, + {DMM_INDEX, OMAP44XX_DMM_PAT_VIEW, 2, 0x00000240}, + {DMM_INDEX, OMAP44XX_DMM_PAT_VIEW_MAP, 4, 0x00000248}, + {DMM_INDEX, OMAP44XX_DMM_PAT_VIEW_MAP_BASE, 1, 0x00000258}, + {DMM_INDEX, OMAP44XX_DMM_PAT_IRQENABLE_SET, 1, 0x0000025C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DESCR, 1, 0x00000260}, + {DMM_INDEX, OMAP44XX_DMM_PAT_AREA, 1, 0x00000264}, + {DMM_INDEX, OMAP44XX_DMM_PAT_CTRL, 1, 0x00000268}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DATA, 1, 0x0000026C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DESCR + 0x10, 1, 0x00000270}, + {DMM_INDEX, OMAP44XX_DMM_PAT_AREA + 0x10, 1, 0x00000274}, + {DMM_INDEX, OMAP44XX_DMM_PAT_CTRL + 0x10, 1, 0x00000278}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DATA + 0x10, 1, 0x0000027C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DESCR + 0x20, 1, 0x00000280}, + {DMM_INDEX, OMAP44XX_DMM_PAT_AREA + 0x20, 1, 0x00000284}, + {DMM_INDEX, OMAP44XX_DMM_PAT_CTRL + 0x20, 1, 0x00000288}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DATA + 0x20, 1, 0x0000028C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DESCR + 0x30, 1, 0x00000290}, + {DMM_INDEX, OMAP44XX_DMM_PAT_AREA + 0x30, 1, 0x00000294}, + {DMM_INDEX, OMAP44XX_DMM_PAT_CTRL + 0x30, 1, 0x00000298}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DATA + 0x30, 1, 0x0000029C}, + {DMM_INDEX, OMAP44XX_DMM_PEG_PRIO, 2, 0x000002A0}, + {DMM_INDEX, OMAP44XX_DMM_PEG_PRIO_PAT, 1, 0x000002A8}, + {L3_CLK1_INDEX, 0x508, 1, 0x000002AC}, + {L3_CLK1_INDEX, 0x510, 1, 0x000002B0}, + {L3_CLK1_INDEX, 0x708, 1, 0x000002B4}, + {L3_CLK1_INDEX, 0x70C, 1, 0x000002B8}, + {L3_CLK1_INDEX, 0x808, 1, 0x000002BC}, + {L3_CLK2_INDEX, 0x1008, 1, 0x000002C0}, + {L3_CLK2_INDEX, 0x1010, 1, 0x000002C4}, + {L3_CLK2_INDEX, 0x1208, 1, 0x000002C8}, + {L3_CLK2_INDEX, 0x1308, 1, 0x000002CC}, + {L3_CLK2_INDEX, 0x130C, 1, 0x000002D0}, + {L3_CLK2_INDEX, 0x1408, 1, 0x000002D4}, + {L3_CLK2_INDEX, 0x140C, 1, 0x000002D8}, + {L3_CLK2_INDEX, 0x1508, 1, 0x000002DC}, + {L3_CLK2_INDEX, 0x150C, 1, 0x000002E0}, + {L3_CLK3_INDEX, 0x208, 1, 0x000002E4}, + {L3_CLK3_INDEX, 0x210, 1, 0x000002E8}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE_OFFSET, 1, 0x000002EC}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE_OFFSET, 1, 0x000002F0}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_SDMA_STATICDEP_RESTORE_OFFSET, 1, 0x000002F4}, + {USBTLL_INDEX, 0x400, 7, 0x000002F8}, + {UHH_INDEX, 0x10, 1, 0x00000314}, + {UHH_INDEX, 0x40, 1, 0x00000318}, + {UHH_INDEX, 0x100, 384, 0x0000031C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE_OFFSET, 1, 0x0000091C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE_OFFSET, 1, 0x00000920}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_SDMA_STATICDEP_RESTORE_OFFSET, 1, 0x00000924}, +}; + +/* + * SAR_RAM2 register layout consist of SYSCTRL_PADCONF_CORE regsiters + */ +static const u32 omap443x_sar_ram2_layout[][4] = { + {CTRL_MODULE_PAD_CORE_INDEX, 0x40, 102, 0x00000000}, +}; + +/* + * SAR_RAM3 and SAR_RAM4 layout is not listed since moslty it's handle by + * secure software. + */ +static const u32 omap443x_sar_ram3_layout[][4] = { + {L4CORE_INDEX, 0x2140, 1, 0x00000000}, + {L4CORE_INDEX, 0x2104, 1, 0x00000004}, + {L4CORE_INDEX, 0x2100, 1, 0x00000008}, + {L4CORE_INDEX, 0x2108, 1, 0x0000000C}, + {L4CORE_INDEX, 0x210C, 1, 0x00000010}, + {L4CORE_INDEX, 0x2110, 1, 0x00000014}, + {L4CORE_INDEX, 0x2114, 1, 0x00000018}, + {L4CORE_INDEX, 0x204088, 14, 0x0000001C}, + {L4CORE_INDEX, 0x206088, 2, 0x00000054}, + {L4CORE_INDEX, 0x20C088, 30, 0x0000005C}, + {L4CORE_INDEX, 0x210088, 30, 0x000000D4}, + {L4CORE_INDEX, 0x212088, 38, 0x0000014C}, + {L4CORE_INDEX, 0x214088, 2, 0x000001E4}, + {L4CORE_INDEX, 0x216088, 2, 0x000001EC}, + {L4CORE_INDEX, 0x218088, 2, 0x000001F4}, + {L4CORE_INDEX, 0x21C088, 2, 0x000001FC}, + {L4CORE_INDEX, 0x21E088, 2, 0x00000204}, + {L4CORE_INDEX, 0x220088, 2, 0x0000020C}, + {L4CORE_INDEX, 0x226088, 6, 0x00000214}, + {L4CORE_INDEX, 0x228088, 2, 0x0000022C}, + {L4CORE_INDEX, 0x22A088, 14, 0x00000234}, + {L4PER_INDEX, 0x218, 1, 0x0000026C}, + {L4PER_INDEX, 0x220, 1, 0x00000270}, + {L4PER_INDEX, 0x228, 1, 0x00000274}, + {L4PER_INDEX, 0x230, 1, 0x00000278}, + {L4PER_INDEX, 0x238, 1, 0x0000027C}, + {L4PER_INDEX, 0x298, 2, 0x00000280}, + {L4PER_INDEX, 0x2A0, 2, 0x00000288}, + {L4PER_INDEX, 0x2A8, 2, 0x00000290}, + {L4PER_INDEX, 0x2B0, 2, 0x00000298}, + {L4PER_INDEX, 0x2B8, 2, 0x000002A0}, + {L4PER_INDEX, 0x304, 1, 0x000002A8}, + {L4PER_INDEX, 0x31C, 1, 0x000002AC}, + {L4PER_INDEX, 0x32C, 1, 0x000002B0}, + {L4PER_INDEX, 0x33C, 1, 0x000002B4}, + {L4PER_INDEX, 0x34C, 1, 0x000002B8}, + {L4PER_INDEX, 0x35C, 1, 0x000002BC}, + {L4PER_INDEX, 0x36C, 1, 0x000002C0}, + {L4PER_INDEX, 0x37C, 1, 0x000002C4}, + {L4PER_INDEX, 0x38C, 1, 0x000002C8}, + {L4PER_INDEX, 0x39C, 1, 0x000002CC}, + {L4PER_INDEX, 0x3AC, 1, 0x000002D0}, + {L4PER_INDEX, 0x3BC, 1, 0x000002D4}, + {L4PER_INDEX, 0x3CC, 1, 0x000002D8}, + {L4PER_INDEX, 0x3D4, 1, 0x000002DC}, + {L4PER_INDEX, 0x3E4, 1, 0x000002E0}, + {L4PER_INDEX, 0x3F4, 1, 0x000002E4}, + {L4PER_INDEX, 0x404, 1, 0x000002E8}, + {L4PER_INDEX, 0x414, 1, 0x000002EC}, + {L4PER_INDEX, 0x42C, 1, 0x000002F0}, + {L4PER_INDEX, 0x43C, 1, 0x000002F4}, + {L4PER_INDEX, 0x44C, 1, 0x000002F8}, + {L4PER_INDEX, 0x45C, 1, 0x000002FC}, + {L4PER_INDEX, 0x46C, 1, 0x00000300}, + {L4PER_INDEX, 0x47C, 1, 0x00000304}, + {L4PER_INDEX, 0x48C, 1, 0x00000308}, + {L4PER_INDEX, 0x49C, 1, 0x0000030C}, + {L4PER_INDEX, 0x4AC, 1, 0x00000310}, + {L4PER_INDEX, 0x4BC, 1, 0x00000314}, + {L4PER_INDEX, 0x4CC, 1, 0x00000318}, + {L4PER_INDEX, 0x4DC, 1, 0x0000031C}, + {L4PER_INDEX, 0x4EC, 1, 0x00000320}, + {L4PER_INDEX, 0x4FC, 1, 0x00000324}, + {L4PER_INDEX, 0x50C, 1, 0x00000328}, + {L4PER_INDEX, 0x51C, 1, 0x0000032C}, + {L4PER_INDEX, 0x52C, 1, 0x00000330}, + {L4PER_INDEX, 0x53C, 1, 0x00000334}, + {L4PER_INDEX, 0x54C, 1, 0x00000338}, + {L4PER_INDEX, 0x55C, 1, 0x0000033C}, + {L4PER_INDEX, 0x56C, 1, 0x00000340}, + {L4PER_INDEX, 0x57C, 1, 0x00000344}, + {L4PER_INDEX, 0x5A4, 1, 0x00000348}, + {L4CORE_INDEX, 0x230, 1, 0x0000034C}, + {L4CORE_INDEX, 0x238, 1, 0x00000350}, + {L4CORE_INDEX, 0x2B0, 2, 0x00000354}, + {L4CORE_INDEX, 0x2B8, 2, 0x0000035C}, + {L4CORE_INDEX, 0x304, 1, 0x00000364}, + {L4CORE_INDEX, 0x31C, 1, 0x00000368}, + {L4CORE_INDEX, 0x32C, 1, 0x0000036C}, + {L4CORE_INDEX, 0x33C, 1, 0x00000370}, + {L4CORE_INDEX, 0x354, 1, 0x00000374}, + {L4CORE_INDEX, 0x35C, 1, 0x00000378}, + {L4CORE_INDEX, 0x36C, 1, 0x0000037C}, + {L4CORE_INDEX, 0x37C, 1, 0x00000380}, + {L4CORE_INDEX, 0x38C, 1, 0x00000384}, + {L4CORE_INDEX, 0x3AC, 1, 0x00000388}, + {L4CORE_INDEX, 0x3BC, 1, 0x0000038C}, + {L4CORE_INDEX, 0x3CC, 1, 0x00000390}, + {L4CORE_INDEX, 0x3DC, 1, 0x00000394}, + {L4CORE_INDEX, 0x3EC, 1, 0x00000398}, + {L4CORE_INDEX, 0x3FC, 1, 0x0000039C}, + {L4CORE_INDEX, 0x40C, 1, 0x000003A0}, + {L4CORE_INDEX, 0x41C, 1, 0x000003A4}, + {L4CORE_INDEX, 0x42C, 1, 0x000003A8}, + {L4CORE_INDEX, 0x43C, 1, 0x000003AC}, + {L4CORE_INDEX, 0x44C, 1, 0x000003B0}, + {L4CORE_INDEX, 0x45C, 1, 0x000003B4}, + {L4CORE_INDEX, 0x46C, 1, 0x000003B8}, + {L4CORE_INDEX, 0x47C, 1, 0x000003BC}, + {L4CORE_INDEX, 0x48C, 1, 0x000003C0}, + {L4CORE_INDEX, 0x49C, 1, 0x000003C4}, + {L4CORE_INDEX, 0x4AC, 1, 0x000003C8}, + {L4CORE_INDEX, 0x4BC, 1, 0x000003CC}, + {L4CORE_INDEX, 0x4CC, 1, 0x000003D0}, + {L4CORE_INDEX, 0x4DC, 1, 0x000003D4}, + {L4CORE_INDEX, 0x4EC, 1, 0x000003D8}, + {L4CORE_INDEX, 0x4FC, 1, 0x000003DC}, + {L4CORE_INDEX, 0x50C, 1, 0x000003E0}, + {L4CORE_INDEX, 0x51C, 1, 0x000003E4}, + {L4CORE_INDEX, 0x52C, 1, 0x000003E8}, + {L4CORE_INDEX, 0x53C, 1, 0x000003EC}, + {L4CORE_INDEX, 0x54C, 1, 0x000003F0}, + {L4CORE_INDEX, 0x55C, 1, 0x000003F4}, + {L4CORE_INDEX, 0x56C, 1, 0x000003F8}, + {L4CORE_INDEX, 0x574, 1, 0x000003FC}, + {L4CORE_INDEX, 0x584, 1, 0x00000400}, + {L4CORE_INDEX, 0x594, 1, 0x00000404}, + {L4CORE_INDEX, 0x5A4, 1, 0x00000408}, + {L4CORE_INDEX, 0x5B4, 1, 0x0000040C}, + {L4CORE_INDEX, 0x5C4, 1, 0x00000410}, + {L4CORE_INDEX, 0x5D4, 1, 0x00000414}, + {L4CORE_INDEX, 0x5DC, 1, 0x00000418}, +}; + + +static const u32 omap446x_sar_ram1_layout[][4] = { + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_CONFIG_2, 1, 0x00000000}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_CONFIG, 1, 0x00000004}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_REF_CTRL, 1, 0x00000008}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW, 1, 0x0000000C}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_1, 1, 0x00000010}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_1_SHDW, 1, 0x00000014}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_2, 1, 0x00000018}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_2_SHDW, 1, 0x0000001C}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_3, 1, 0x00000020}, + {EMIF1_INDEX, OMAP44XX_EMIF_SDRAM_TIM_3_SHDW, 1, 0x00000024}, + {EMIF1_INDEX, OMAP44XX_EMIF_LPDDR2_NVM_TIM, 1, 0x00000028}, + {EMIF1_INDEX, OMAP44XX_EMIF_LPDDR2_NVM_TIM_SHDW, 1, 0x0000002C}, + {EMIF1_INDEX, OMAP44XX_EMIF_PWR_MGMT_CTRL, 1, 0x00000030}, + {EMIF1_INDEX, OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW, 1, 0x00000034}, + {EMIF1_INDEX, OMAP44XX_EMIF_OCP_CONFIG, 1, 0x00000038}, + {EMIF1_INDEX, OMAP44XX_EMIF_PERF_CNT_CFG, 1, 0x0000003C}, + {EMIF1_INDEX, OMAP44XX_EMIF_PERF_CNT_SEL, 1, 0x00000040}, + {EMIF1_INDEX, OMAP44XX_EMIF_READ_IDLE_CTRL, 1, 0x00000044}, + {EMIF1_INDEX, OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW, 1, 0x00000048}, + {EMIF1_INDEX, OMAP44XX_EMIF_IRQENABLE_SET_SYS, 1, 0x0000004C}, + {EMIF1_INDEX, OMAP44XX_EMIF_IRQENABLE_SET_LL, 1, 0x00000050}, + {EMIF1_INDEX, OMAP44XX_EMIF_ZQ_CONFIG, 1, 0x00000054}, + {EMIF1_INDEX, OMAP44XX_EMIF_TEMP_ALERT_CONFIG, 1, 0x00000058}, + {EMIF1_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_1, 1, 0x0000005C}, + {EMIF1_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW, 1, 0x00000060}, + {EMIF1_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_2, 1, 0x00000064}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_CONFIG_2, 1, 0x00000068}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_CONFIG, 1, 0x0000006C}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_REF_CTRL, 1, 0x00000070}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW, 1, 0x00000074}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_1, 1, 0x00000078}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_1_SHDW, 1, 0x0000007C}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_2, 1, 0x00000080}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_2_SHDW, 1, 0x00000084}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_3, 1, 0x00000088}, + {EMIF2_INDEX, OMAP44XX_EMIF_SDRAM_TIM_3_SHDW, 1, 0x0000008C}, + {EMIF2_INDEX, OMAP44XX_EMIF_LPDDR2_NVM_TIM, 1, 0x00000090}, + {EMIF2_INDEX, OMAP44XX_EMIF_LPDDR2_NVM_TIM_SHDW, 1, 0x00000094}, + {EMIF2_INDEX, OMAP44XX_EMIF_PWR_MGMT_CTRL, 1, 0x00000098}, + {EMIF2_INDEX, OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW, 1, 0x0000009C}, + {EMIF2_INDEX, OMAP44XX_EMIF_OCP_CONFIG, 1, 0x000000A0}, + {EMIF2_INDEX, OMAP44XX_EMIF_PERF_CNT_CFG, 1, 0x000000A4}, + {EMIF2_INDEX, OMAP44XX_EMIF_PERF_CNT_SEL, 1, 0x000000A8}, + {EMIF2_INDEX, OMAP44XX_EMIF_READ_IDLE_CTRL, 1, 0x000000AC}, + {EMIF2_INDEX, OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW, 1, 0x000000B0}, + {EMIF2_INDEX, OMAP44XX_EMIF_IRQENABLE_SET_SYS, 1, 0x000000B4}, + {EMIF2_INDEX, OMAP44XX_EMIF_IRQENABLE_SET_LL, 1, 0x000000B8}, + {EMIF2_INDEX, OMAP44XX_EMIF_ZQ_CONFIG, 1, 0x000000BC}, + {EMIF2_INDEX, OMAP44XX_EMIF_TEMP_ALERT_CONFIG, 1, 0x000000C0}, + {EMIF2_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_1, 1, 0x000000C4}, + {EMIF2_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW, 1, 0x000000C8}, + {EMIF2_INDEX, OMAP44XX_EMIF_DDR_PHY_CTRL_2, 1, 0x000000CC}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_MEMIF_CLKSTCTRL_RESTORE_OFFSET, 1, 0x000000D0}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_CLKSEL_CORE_RESTORE_OFFSET, 1, 0x000000D4}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M2_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000D8}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M3_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000DC}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M4_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000E0}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M5_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000E4}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M6_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000E8}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DIV_M7_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000EC}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_CLKSEL_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000F0}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000F4}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000F8}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_CLKMODE_DPLL_CORE_RESTORE_OFFSET, 1, 0x000000FC}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_SHADOW_FREQ_CONFIG2_RESTORE_OFFSET, 1, 0x00000100}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_SHADOW_FREQ_CONFIG1_RESTORE_OFFSET, 1, 0x00000104}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_AUTOIDLE_DPLL_CORE_RESTORE_OFFSET, 1, 0x00000108}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_MPU_CLKSTCTRL_RESTORE_OFFSET, 1, 0x0000010C}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_CM1_PROFILING_CLKCTRL_RESTORE_OFFSET, 1, 0x00000110}, + {CM1_INDEX, OMAP4430_CM1_RESTORE_INST + + OMAP4_CM_DYN_DEP_PRESCAL_RESTORE_OFFSET, 1, 0x00000114}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3_1_CLKSTCTRL_RESTORE_OFFSET, 1, 0x00000118}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3_2_CLKSTCTRL_RESTORE_OFFSET, 1, 0x0000011C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L4CFG_CLKSTCTRL_RESTORE_OFFSET, 1, 0x00000120}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_MEMIF_CLKSTCTRL_RESTORE_OFFSET, 1, 0x00000124}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L4PER_CLKSTCTRL_RESTORE_OFFSET, 1, 0x00000128}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_CLKSTCTRL_RESTORE_OFFSET, 1, 0x0000012C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INSTR_L3_3_CLKCTRL_RESTORE_OFFSET, 1, 0x00000130}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE_OFFSET, 1, 0x00000134}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE_OFFSET, 1, 0x00000138}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_CM2_PROFILING_CLKCTRL_RESTORE_OFFSET, 1, 0x0000013C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_D2D_STATICDEP_RESTORE_OFFSET, 1, 0x00000140}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3_1_DYNAMICDEP_RESTORE_OFFSET, 1, 0x00000144}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3_2_DYNAMICDEP_RESTORE_OFFSET, 1, 0x00000148}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_D2D_DYNAMICDEP_RESTORE_OFFSET, 1, 0x0000014C}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L4CFG_DYNAMICDEP_RESTORE_OFFSET, 1, 0x00000150}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L4PER_DYNAMICDEP_RESTORE_OFFSET, 1, 0x00000154}, + {C2C_INDEX, 0x0C, 1, 0x00000158}, + {C2C_INDEX, 0x10, 1, 0x0000015C}, + {C2C_INDEX, 0x28, 1, 0x00000160}, + {C2C_INDEX, 0x40, 1, 0x00000164}, + {C2C_INDEX, 0x44, 1, 0x00000168}, + {C2C_INDEX, 0x70, 1, 0x0000016C}, + {C2C_INDEX, 0x74, 1, 0x00000170}, + {C2C_INDEX, 0x84, 1, 0x00000174}, + {C2C_INDEX, 0x88, 1, 0x00000178}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PADCONF_GLOBAL, 15, 0x0000017C}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE, 14, 0x000001B8}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_0, 8, 0x000001F0}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_BUS_HOLD, 1, 0x00000210}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_C2C, 1, 0x00000214}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_1, 1, 0x00000218}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_2, 1, 0x0000021C}, + {CTRL_MODULE_PAD_CORE_INDEX, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_4, 1, 0x00000220}, + {L4CORE_INDEX, 0x2350, 1, 0x00000224}, + {DMM_INDEX, OMAP44XX_DMM_LISA_MAP, 4, 0x000000228}, + {DMM_INDEX, OMAP44XX_DMM_LISA_LOCK, 1, 0x00000238}, + {DMM_INDEX, OMAP44XX_DMM_TILER_OR, 2, 0x0000023C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_VIEW, 2, 0x00000244}, + {DMM_INDEX, OMAP44XX_DMM_PAT_VIEW_MAP, 4, 0x0000024C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_VIEW_MAP_BASE, 1, 0x0000025C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_IRQENABLE_SET, 1, 0x00000260}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DESCR, 1, 0x00000264}, + {DMM_INDEX, OMAP44XX_DMM_PAT_AREA, 1, 0x00000268}, + {DMM_INDEX, OMAP44XX_DMM_PAT_CTRL, 1, 0x0000026C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DATA, 1, 0x00000270}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DESCR + 0x10, 1, 0x00000274}, + {DMM_INDEX, OMAP44XX_DMM_PAT_AREA + 0x10, 1, 0x00000278}, + {DMM_INDEX, OMAP44XX_DMM_PAT_CTRL + 0x10, 1, 0x0000027C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DATA + 0x10, 1, 0x00000280}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DESCR + 0x20, 1, 0x00000284}, + {DMM_INDEX, OMAP44XX_DMM_PAT_AREA + 0x20, 1, 0x00000288}, + {DMM_INDEX, OMAP44XX_DMM_PAT_CTRL + 0x20, 1, 0x0000028C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DATA + 0x20, 1, 0x00000290}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DESCR + 0x30, 1, 0x00000294}, + {DMM_INDEX, OMAP44XX_DMM_PAT_AREA + 0x30, 1, 0x00000298}, + {DMM_INDEX, OMAP44XX_DMM_PAT_CTRL + 0x30, 1, 0x0000029C}, + {DMM_INDEX, OMAP44XX_DMM_PAT_DATA + 0x30, 1, 0x000002A0}, + {DMM_INDEX, OMAP44XX_DMM_PEG_PRIO, 2, 0x000002A4}, + {DMM_INDEX, OMAP44XX_DMM_PEG_PRIO_PAT, 1, 0x000002AC}, + {L3_CLK1_INDEX, 0x508, 1, 0x000002B0}, + {L3_CLK1_INDEX, 0x510, 1, 0x000002B4}, + {L3_CLK1_INDEX, 0x708, 1, 0x000002B8}, + {L3_CLK1_INDEX, 0x70C, 1, 0x000002BC}, + {L3_CLK1_INDEX, 0x808, 1, 0x000002C0}, + {L3_CLK2_INDEX, 0x1008, 1, 0x000002C4}, + {L3_CLK2_INDEX, 0x1010, 1, 0x000002C8}, + {L3_CLK2_INDEX, 0x1208, 1, 0x000002CC}, + {L3_CLK2_INDEX, 0x1308, 1, 0x000002D0}, + {L3_CLK2_INDEX, 0x130C, 1, 0x000002D4}, + {L3_CLK2_INDEX, 0x1408, 1, 0x000002D8}, + {L3_CLK2_INDEX, 0x140C, 1, 0x000002DC}, + {L3_CLK2_INDEX, 0x1508, 1, 0x000002E0}, + {L3_CLK2_INDEX, 0x150C, 1, 0x000002E4}, + {L3_CLK3_INDEX, 0x208, 1, 0x000002E8}, + {L3_CLK3_INDEX, 0x210, 1, 0x000002EC}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE_OFFSET, 1, 0x000002F0}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE_OFFSET, 1, 0x000002F4}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_SDMA_STATICDEP_RESTORE_OFFSET, 1, 0x000002F8}, + {USBTLL_INDEX, 0x400, 7, 0x000002FC}, + {UHH_INDEX, 0x10, 1, 0x00000318}, + {UHH_INDEX, 0x40, 1, 0x0000031C}, + {UHH_INDEX, 0x100, 384, 0x00000320}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE_OFFSET, 1, 0x00000920}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE_OFFSET, 1, 0x00000924}, + {CM2_INDEX, OMAP4430_CM2_RESTORE_INST + + OMAP4_CM_SDMA_STATICDEP_RESTORE_OFFSET, 1, 0x00000928}, +}; + +/* + * SAR_RAM2 register layout consist of SYSCTRL_PADCONF_CORE regsiters + */ +static const u32 omap446x_sar_ram2_layout[][4] = { + {CTRL_MODULE_PAD_CORE_INDEX, 0x40, 102, 0x00000000}, + {CTRL_MODULE_PAD_CORE_INDEX, 0x1f4, 1, 0x00000198}, +}; + +/* + * SAR_RAM3 and SAR_RAM4 layout is not listed since moslty it's handle by + * secure software. + */ +static const u32 omap446x_sar_ram3_layout[][4] = { + {L4CORE_INDEX, 0x2140, 1, 0x00000000}, + {L4CORE_INDEX, 0x2104, 1, 0x00000004}, + {L4CORE_INDEX, 0x2100, 1, 0x00000008}, + {L4CORE_INDEX, 0x2108, 1, 0x0000000C}, + {L4CORE_INDEX, 0x210C, 1, 0x00000010}, + {L4CORE_INDEX, 0x2110, 1, 0x00000014}, + {L4CORE_INDEX, 0x2114, 1, 0x00000018}, + {L4CORE_INDEX, 0x204088, 14, 0x0000001C}, + {L4CORE_INDEX, 0x206088, 2, 0x00000054}, + {L4CORE_INDEX, 0x20C088, 30, 0x0000005C}, + {L4CORE_INDEX, 0x210088, 30, 0x000000D4}, + {L4CORE_INDEX, 0x212088, 38, 0x0000014C}, + {L4CORE_INDEX, 0x214088, 2, 0x000001E4}, + {L4CORE_INDEX, 0x216088, 2, 0x000001EC}, + {L4CORE_INDEX, 0x218088, 2, 0x000001F4}, + {L4CORE_INDEX, 0x21C088, 2, 0x000001FC}, + {L4CORE_INDEX, 0x21E088, 2, 0x00000204}, + {L4CORE_INDEX, 0x220088, 2, 0x0000020C}, + {L4CORE_INDEX, 0x226088, 6, 0x00000214}, + {L4CORE_INDEX, 0x228088, 2, 0x0000022C}, + {L4CORE_INDEX, 0x22A088, 14, 0x00000234}, + {L4CORE_INDEX, 0x20A088, 30, 0x0000026C}, + {L4PER_INDEX, 0x218, 1, 0x000002E4}, + {L4PER_INDEX, 0x220, 1, 0x000002E8}, + {L4PER_INDEX, 0x228, 1, 0x000002EC}, + {L4PER_INDEX, 0x230, 1, 0x000002F0}, + {L4PER_INDEX, 0x238, 1, 0x000002F4}, + {L4PER_INDEX, 0x298, 2, 0x000002F8}, + {L4PER_INDEX, 0x2A0, 2, 0x00000300}, + {L4PER_INDEX, 0x2A8, 2, 0x00000308}, + {L4PER_INDEX, 0x2B0, 2, 0x00000310}, + {L4PER_INDEX, 0x2B8, 2, 0x00000318}, + {L4PER_INDEX, 0x304, 1, 0x00000320}, + {L4PER_INDEX, 0x31C, 1, 0x00000324}, + {L4PER_INDEX, 0x32C, 1, 0x00000328}, + {L4PER_INDEX, 0x33C, 1, 0x0000032C}, + {L4PER_INDEX, 0x34C, 1, 0x00000330}, + {L4PER_INDEX, 0x35C, 1, 0x00000334}, + {L4PER_INDEX, 0x36C, 1, 0x00000338}, + {L4PER_INDEX, 0x37C, 1, 0x0000033C}, + {L4PER_INDEX, 0x38C, 1, 0x00000340}, + {L4PER_INDEX, 0x39C, 1, 0x00000344}, + {L4PER_INDEX, 0x3AC, 1, 0x00000348}, + {L4PER_INDEX, 0x3BC, 1, 0x0000034C}, + {L4PER_INDEX, 0x3CC, 1, 0x00000350}, + {L4PER_INDEX, 0x3D4, 1, 0x00000354}, + {L4PER_INDEX, 0x3E4, 1, 0x00000358}, + {L4PER_INDEX, 0x3F4, 1, 0x0000035C}, + {L4PER_INDEX, 0x404, 1, 0x00000360}, + {L4PER_INDEX, 0x414, 1, 0x00000364}, + {L4PER_INDEX, 0x42C, 1, 0x00000368}, + {L4PER_INDEX, 0x43C, 1, 0x0000036C}, + {L4PER_INDEX, 0x44C, 1, 0x00000370}, + {L4PER_INDEX, 0x45C, 1, 0x00000374}, + {L4PER_INDEX, 0x46C, 1, 0x00000378}, + {L4PER_INDEX, 0x47C, 1, 0x0000037C}, + {L4PER_INDEX, 0x48C, 1, 0x00000380}, + {L4PER_INDEX, 0x49C, 1, 0x00000384}, + {L4PER_INDEX, 0x4AC, 1, 0x00000388}, + {L4PER_INDEX, 0x4BC, 1, 0x0000038C}, + {L4PER_INDEX, 0x4CC, 1, 0x00000390}, + {L4PER_INDEX, 0x4DC, 1, 0x00000394}, + {L4PER_INDEX, 0x4EC, 1, 0x00000398}, + {L4PER_INDEX, 0x4FC, 1, 0x0000039C}, + {L4PER_INDEX, 0x50C, 1, 0x000003A0}, + {L4PER_INDEX, 0x51C, 1, 0x000003A4}, + {L4PER_INDEX, 0x52C, 1, 0x000003A8}, + {L4PER_INDEX, 0x53C, 1, 0x000003AC}, + {L4PER_INDEX, 0x54C, 1, 0x000003B0}, + {L4PER_INDEX, 0x55C, 1, 0x000003B4}, + {L4PER_INDEX, 0x56C, 1, 0x000003B8}, + {L4PER_INDEX, 0x57C, 1, 0x000003BC}, + {L4PER_INDEX, 0x5A4, 1, 0x000003C0}, + {L4CORE_INDEX, 0x230, 1, 0x000003C4}, + {L4CORE_INDEX, 0x238, 1, 0x000003C8}, + {L4CORE_INDEX, 0x2B0, 2, 0x000003CC}, + {L4CORE_INDEX, 0x2B8, 2, 0x000003D4}, + {L4CORE_INDEX, 0x304, 1, 0x000003DC}, + {L4CORE_INDEX, 0x31C, 1, 0x000003E0}, + {L4CORE_INDEX, 0x32C, 1, 0x000003E4}, + {L4CORE_INDEX, 0x33C, 1, 0x000003E8}, + {L4CORE_INDEX, 0x354, 1, 0x000003EC}, + {L4CORE_INDEX, 0x35C, 1, 0x000003F0}, + {L4CORE_INDEX, 0x36C, 1, 0x000003F4}, + {L4CORE_INDEX, 0x37C, 1, 0x000003F8}, + {L4CORE_INDEX, 0x38C, 1, 0x000003FC}, + {L4CORE_INDEX, 0x3AC, 1, 0x00000400}, + {L4CORE_INDEX, 0x3BC, 1, 0x00000404}, + {L4CORE_INDEX, 0x3CC, 1, 0x00000408}, + {L4CORE_INDEX, 0x3DC, 1, 0x0000040C}, + {L4CORE_INDEX, 0x3EC, 1, 0x00000410}, + {L4CORE_INDEX, 0x3FC, 1, 0x00000414}, + {L4CORE_INDEX, 0x40C, 1, 0x00000418}, + {L4CORE_INDEX, 0x41C, 1, 0x0000041C}, + {L4CORE_INDEX, 0x42C, 1, 0x00000420}, + {L4CORE_INDEX, 0x43C, 1, 0x00000424}, + {L4CORE_INDEX, 0x44C, 1, 0x00000428}, + {L4CORE_INDEX, 0x45C, 1, 0x0000042C}, + {L4CORE_INDEX, 0x46C, 1, 0x00000430}, + {L4CORE_INDEX, 0x47C, 1, 0x00000434}, + {L4CORE_INDEX, 0x48C, 1, 0x00000438}, + {L4CORE_INDEX, 0x49C, 1, 0x0000043C}, + {L4CORE_INDEX, 0x4AC, 1, 0x00000440}, + {L4CORE_INDEX, 0x4BC, 1, 0x00000444}, + {L4CORE_INDEX, 0x4CC, 1, 0x00000448}, + {L4CORE_INDEX, 0x4DC, 1, 0x0000044C}, + {L4CORE_INDEX, 0x4EC, 1, 0x00000450}, + {L4CORE_INDEX, 0x4FC, 1, 0x00000454}, + {L4CORE_INDEX, 0x50C, 1, 0x00000458}, + {L4CORE_INDEX, 0x51C, 1, 0x0000045C}, + {L4CORE_INDEX, 0x52C, 1, 0x00000460}, + {L4CORE_INDEX, 0x53C, 1, 0x00000464}, + {L4CORE_INDEX, 0x54C, 1, 0x00000468}, + {L4CORE_INDEX, 0x55C, 1, 0x0000046C}, + {L4CORE_INDEX, 0x56C, 1, 0x00000470}, + {L4CORE_INDEX, 0x574, 1, 0x00000474}, + {L4CORE_INDEX, 0x584, 1, 0x00000478}, + {L4CORE_INDEX, 0x594, 1, 0x0000047C}, + {L4CORE_INDEX, 0x5A4, 1, 0x00000480}, + {L4CORE_INDEX, 0x5B4, 1, 0x00000484}, + {L4CORE_INDEX, 0x5C4, 1, 0x00000488}, + {L4CORE_INDEX, 0x5D4, 1, 0x0000048C}, + {L4CORE_INDEX, 0x5DC, 1, 0x00000490}, + {L4CORE_INDEX, 0x5E4, 1, 0x00000494}, + {L4CORE_INDEX, 0x5EC, 1, 0x00000498}, + {L4CORE_INDEX, 0x5F4, 1, 0x0000049C}, + {L4CORE_INDEX, 0x5FC, 1, 0x000004A0}, +}; + +/* + * omap_sar_save : + * common routine to save the registers to SAR RAM with the + * given parameters + * @nb_regs - Number of registers to saved + * @sar_bank_offset - where to backup + * @sar_layout - constant table containing the backup info + */ +static void sar_save(u32 nb_regs, u32 sar_bank, const u32 sar_layout_table[][4]) +{ + u32 reg_val, size, i, j; + void __iomem *reg_read_addr, *sar_wr_addr; + + for (i = 0; i < nb_regs; i++) { + if (omap4_sar_modules[(sar_layout_table[i][MODULE_ADDR_IDX])]) { + size = sar_layout_table[i][MODULE_NB_REGS_IDX]; + reg_read_addr = + omap4_sar_modules[sar_layout_table[i] + [MODULE_ADDR_IDX]] + + sar_layout_table[i][MODULE_OFFSET_IDX]; + sar_wr_addr = sar_ram_base + sar_bank + + sar_layout_table[i][SAR_RAM_OFFSET_IDX]; + for (j = 0; j < size; j++) { + reg_val = __raw_readl(reg_read_addr + j * 4); + __raw_writel(reg_val, sar_wr_addr + j * 4); + } + } + } +} + +static void save_sar_bank3(void) +{ + struct clockdomain *l4_secure_clkdm; + + /* + * Not supported on ES1.0 silicon + */ + if (omap_rev() == OMAP4430_REV_ES1_0) { + WARN_ONCE(1, "omap4: SAR backup not supported on ES1.0 ..\n"); + return; + } + + l4_secure_clkdm = clkdm_lookup("l4_secure_clkdm"); + clkdm_wakeup(l4_secure_clkdm); + + if (cpu_is_omap446x()) + sar_save(ARRAY_SIZE(omap446x_sar_ram3_layout), SAR_BANK3_OFFSET, + omap446x_sar_ram3_layout); + else + sar_save(ARRAY_SIZE(omap443x_sar_ram3_layout), SAR_BANK3_OFFSET, + omap443x_sar_ram3_layout); + + clkdm_allow_idle(l4_secure_clkdm); +} + +static int omap4_sar_not_accessible(void) +{ + u32 usbhost_state, usbtll_state; + + /* + * Make sure that USB host and TLL modules are not + * enabled before attempting to save the context + * registers, otherwise this will trigger an exception. + */ + usbhost_state = omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION, + OMAP4430_CM2_L3INIT_INST, + OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET) + & (OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK); + + usbtll_state = omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION, + OMAP4430_CM2_L3INIT_INST, + OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET) + & OMAP4430_IDLEST_MASK; + + if ((usbhost_state == (OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK)) && + (usbtll_state == (OMAP4430_IDLEST_MASK))) + return 0; + else + return -EBUSY; +} + + /* + * omap4_sar_save - + * Save the context to SAR_RAM1 and SAR_RAM2 as per + * omap4xxx_sar_ram1_layout and omap4xxx_sar_ram2_layout for the device OFF + * mode + */ +int omap4_sar_save(void) +{ + /* + * Not supported on ES1.0 silicon + */ + if (omap_rev() == OMAP4430_REV_ES1_0) { + WARN_ONCE(1, "omap4: SAR backup not supported on ES1.0 ..\n"); + return -ENODEV; + } + + if (omap4_sar_not_accessible()) { + pr_debug("%s: USB SAR CNTX registers are not accessible!\n", + __func__); + return -EBUSY; + } + + /* + * SAR bits and clocks needs to be enabled + */ + clkdm_wakeup(l3init_clkdm); + pwrdm_enable_hdwr_sar(l3init_pwrdm); + clk_enable(usb_host_ck); + clk_enable(usb_tll_ck); + + /* Save SAR BANK1 */ + if (cpu_is_omap446x()) + sar_save(ARRAY_SIZE(omap446x_sar_ram1_layout), SAR_BANK1_OFFSET, + omap446x_sar_ram1_layout); + else + sar_save(ARRAY_SIZE(omap443x_sar_ram1_layout), SAR_BANK1_OFFSET, + omap443x_sar_ram1_layout); + + clk_disable(usb_host_ck); + clk_disable(usb_tll_ck); + pwrdm_disable_hdwr_sar(l3init_pwrdm); + clkdm_allow_idle(l3init_clkdm); + + /* Save SAR BANK2 */ + if (cpu_is_omap446x()) + sar_save(ARRAY_SIZE(omap446x_sar_ram2_layout), SAR_BANK2_OFFSET, + omap446x_sar_ram2_layout); + else + sar_save(ARRAY_SIZE(omap443x_sar_ram2_layout), SAR_BANK2_OFFSET, + omap443x_sar_ram2_layout); + + return 0; +} + +/** + * omap4_sar_overwrite : + * This API overwrite some of the SAR locations as a special cases + * The register content to be saved can be the register value before + * going into OFF-mode or a value that is required on wake up. This means + * that the restored register value can be different from the last value + * of the register before going into OFF-mode + * - CM1 and CM2 configuration + * Bits 0 of the CM_SHADOW_FREQ_CONFIG1 regiser and the + * CM_SHADOW_FREQ_CONFIG2 register are self-clearing and must + * be set at restore time. Thus, these data must always be + * overwritten in the SAR RAM. + * - Because USBHOSTHS and USBTLL restore needs a particular + * sequencing, the software must overwrite data read from + * the following registers implied in phase2a and phase 2b + */ +void omap4_sar_overwrite(void) +{ + u32 val = 0; + u32 offset = 0; + + if (cpu_is_omap446x()) + offset = 0x04; + + /* Overwriting Phase1 data to be restored */ + /* CM2 MEMIF_CLKTRCTRL = SW_WKUP, before FREQ UPDATE */ + __raw_writel(0x2, sar_ram_base + SAR_BANK1_OFFSET + 0xd0); + /* CM1 CM_SHADOW_FREQ_CONFIG2, Enable FREQ UPDATE */ + val = __raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG2); + /* + * FIXME: Implement FREQ UPDATE for L#/M5 before enabling this + * val |= 1 << OMAP4430_FREQ_UPDATE_SHIFT; + */ + __raw_writel(val, sar_ram_base + SAR_BANK1_OFFSET + 0x100); + /* CM1 CM_SHADOW_FREQ_CONFIG1, Enable FREQ UPDATE */ + val = __raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1); + val |= 1 << OMAP4430_FREQ_UPDATE_SHIFT; + val &= ~OMAP4430_DLL_OVERRIDE_MASK; + __raw_writel(val, sar_ram_base + SAR_BANK1_OFFSET + 0x104); + /* CM2 MEMIF_CLKTRCTRL = HW_AUTO, after FREQ UPDATE */ + __raw_writel(0x3, sar_ram_base + SAR_BANK1_OFFSET + 0x124); + + /* Overwriting Phase2a data to be restored */ + /* CM_L3INIT_USB_HOST_CLKCTRL: SAR_MODE = 1, MODULEMODE = 2 */ + __raw_writel(0x00000012, + sar_ram_base + SAR_BANK1_OFFSET + 0x2ec + offset); + /* CM_L3INIT_USB_TLL_CLKCTRL: SAR_MODE = 1, MODULEMODE = 1 */ + __raw_writel(0x00000011, + sar_ram_base + SAR_BANK1_OFFSET + 0x2f0 + offset); + /* CM2 CM_SDMA_STATICDEP : Enable static depedency for SAR modules */ + __raw_writel(0x000090e8, + sar_ram_base + SAR_BANK1_OFFSET + 0x2f4 + offset); + + /* Overwriting Phase2b data to be restored */ + /* CM_L3INIT_USB_HOST_CLKCTRL: SAR_MODE = 0, MODULEMODE = 0 */ + val = __raw_readl(OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL); + val &= (OMAP4430_CLKSEL_UTMI_P1_MASK | OMAP4430_CLKSEL_UTMI_P2_MASK); + __raw_writel(val, sar_ram_base + SAR_BANK1_OFFSET + 0x91c + offset); + /* CM_L3INIT_USB_TLL_CLKCTRL: SAR_MODE = 0, MODULEMODE = 0 */ + __raw_writel(0x0000000, + sar_ram_base + SAR_BANK1_OFFSET + 0x920 + offset); + /* CM2 CM_SDMA_STATICDEP : Clear the static depedency */ + __raw_writel(0x00000040, + sar_ram_base + SAR_BANK1_OFFSET + 0x924 + offset); + + /* readback to ensure data reaches to SAR RAM */ + barrier(); + val = __raw_readl(sar_ram_base + SAR_BANK1_OFFSET + 0x924 + offset); +} + +void __iomem *omap4_get_sar_ram_base(void) +{ + return sar_ram_base; +} + +/* + * SAR RAM used to save and restore the HW + * context in low power modes + */ +static int __init omap4_sar_ram_init(void) +{ + /* + * To avoid code running on other OMAPs in + * multi-omap builds + */ + if (!cpu_is_omap44xx()) + return -ENODEV; + + /* + * Static mapping, never released Actual SAR area used is 8K it's + * spaced over 16K address with some part is reserved. + */ + sar_ram_base = ioremap(OMAP44XX_SAR_RAM_BASE, SZ_16K); + BUG_ON(!sar_ram_base); + + /* + * All these are static mappings so ioremap() will + * just return with mapped VA + */ + omap4_sar_modules[EMIF1_INDEX] = ioremap(OMAP44XX_EMIF1, SZ_1M); + BUG_ON(!omap4_sar_modules[EMIF1_INDEX]); + omap4_sar_modules[EMIF2_INDEX] = ioremap(OMAP44XX_EMIF2, SZ_1M); + BUG_ON(!omap4_sar_modules[EMIF2_INDEX]); + omap4_sar_modules[DMM_INDEX] = ioremap(OMAP44XX_DMM_BASE, SZ_1M); + BUG_ON(!omap4_sar_modules[DMM_INDEX]); + omap4_sar_modules[CM1_INDEX] = ioremap(OMAP4430_CM1_BASE, SZ_8K); + BUG_ON(!omap4_sar_modules[CM1_INDEX]); + omap4_sar_modules[CM2_INDEX] = ioremap(OMAP4430_CM2_BASE, SZ_8K); + BUG_ON(!omap4_sar_modules[CM2_INDEX]); + omap4_sar_modules[C2C_INDEX] = ioremap(OMAP44XX_C2C_BASE, SZ_1M); + BUG_ON(!omap4_sar_modules[C2C_INDEX]); + omap4_sar_modules[CTRL_MODULE_PAD_CORE_INDEX] = + ioremap(OMAP443X_CTRL_BASE, SZ_4K); + BUG_ON(!omap4_sar_modules[CTRL_MODULE_PAD_CORE_INDEX]); + omap4_sar_modules[L3_CLK1_INDEX] = ioremap(L3_44XX_BASE_CLK1, SZ_1M); + BUG_ON(!omap4_sar_modules[L3_CLK1_INDEX]); + omap4_sar_modules[L3_CLK2_INDEX] = ioremap(L3_44XX_BASE_CLK2, SZ_1M); + BUG_ON(!omap4_sar_modules[L3_CLK2_INDEX]); + omap4_sar_modules[L3_CLK3_INDEX] = ioremap(L3_44XX_BASE_CLK3, SZ_1M); + BUG_ON(!omap4_sar_modules[L3_CLK3_INDEX]); + omap4_sar_modules[USBTLL_INDEX] = ioremap(OMAP44XX_USBTLL_BASE, SZ_1M); + BUG_ON(!omap4_sar_modules[USBTLL_INDEX]); + omap4_sar_modules[UHH_INDEX] = ioremap(OMAP44XX_UHH_CONFIG_BASE, SZ_1M); + BUG_ON(!omap4_sar_modules[UHH_INDEX]); + omap4_sar_modules[L4CORE_INDEX] = ioremap(L4_44XX_PHYS, SZ_4M); + BUG_ON(!omap4_sar_modules[L4CORE_INDEX]); + omap4_sar_modules[L4PER_INDEX] = ioremap(L4_PER_44XX_PHYS, SZ_4M); + BUG_ON(!omap4_sar_modules[L4PER_INDEX]); + + /* + * SAR BANK3 contains all firewall settings and it's saved through + * secure API on HS device. On GP device these registers are + * meaningless but still needs to be saved. Otherwise Auto-restore + * phase DMA takes an abort. Hence save these conents only once + * in init to avoid the issue while waking up from device OFF + */ + if (omap_type() == OMAP2_DEVICE_TYPE_GP) + save_sar_bank3(); + /* + * Work around for OMAP443x Errata i632: "LPDDR2 Corruption After OFF + * Mode Transition When CS1 Is Used On EMIF": + * Overwrite EMIF1/EMIF2 + * SECURE_EMIF1_SDRAM_CONFIG2_REG + * SECURE_EMIF2_SDRAM_CONFIG2_REG + */ + if (cpu_is_omap443x()) { + void __iomem *secure_ctrl_mod; + + secure_ctrl_mod = ioremap(OMAP4_CTRL_MODULE_WKUP, SZ_4K); + BUG_ON(!secure_ctrl_mod); + + __raw_writel(0x10, secure_ctrl_mod + + OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG); + __raw_writel(0x10, secure_ctrl_mod + + OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG); + wmb(); + iounmap(secure_ctrl_mod); + } + + /* + * L3INIT PD and clocks are needed for SAR save phase + */ + l3init_pwrdm = pwrdm_lookup("l3init_pwrdm"); + if (!l3init_pwrdm) + pr_err("Failed to get l3init_pwrdm\n"); + + l3init_clkdm = clkdm_lookup("l3_init_clkdm"); + if (!l3init_clkdm) + pr_err("Failed to get l3_init_clkdm\n"); + + usb_host_ck = clk_get(NULL, "usb_host_hs_fck"); + if (!usb_host_ck) + pr_err("Could not get usb_host_ck\n"); + + usb_tll_ck = clk_get(NULL, "usb_tll_hs_ick"); + if (!usb_tll_ck) + pr_err("Could not get usb_tll_ck\n"); + + return 0; +} +early_initcall(omap4_sar_ram_init); diff --git a/arch/arm/mach-omap2/omap44xx-smc.S b/arch/arm/mach-omap2/omap44xx-smc.S index e69d37d..83ba6d9 100644 --- a/arch/arm/mach-omap2/omap44xx-smc.S +++ b/arch/arm/mach-omap2/omap44xx-smc.S @@ -31,6 +31,30 @@ ENTRY(omap_smc1) ldmfd sp!, {r2-r12, pc} ENDPROC(omap_smc1) +/* + * Low level common routine to manage secure + * HAL APIs. + * Function signature : u32 omap_smc2(u32 id, u32 falg, u32 pargs) + * @id : Application ID of HAL APIs + * @flag : Flag to indicate the criticality of operation + * @pargs : Physical address of parameter list starting + * with number of parametrs + */ +ENTRY(omap_smc2) + stmfd sp!, {r1-r12, lr} + mov r3, r2 + mov r2, r1 + mov r1, #0x0 @ Process ID + mov r6, #0xff + mov r12, #0x00 @ Secure Service ID + mov r7, #0 + mcr p15, 0, r7, c7, c5, 6 + dsb + dmb + smc #0 + ldmfd sp!, {r1-r12, pc} +END(omap_smc2) + ENTRY(omap_modify_auxcoreboot0) stmfd sp!, {r1-r12, lr} ldr r12, =0x104 diff --git a/arch/arm/mach-omap2/omap4_trim_quirks.c b/arch/arm/mach-omap2/omap4_trim_quirks.c new file mode 100644 index 0000000..dd96726 --- /dev/null +++ b/arch/arm/mach-omap2/omap4_trim_quirks.c @@ -0,0 +1,180 @@ +/* + * OMAP LDO control and configuration + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/cpu.h> + +#include "control.h" +#include "pm.h" +#include <mach/ctrl_module_core_44xx.h> + +#define OMAP4_DPLL_MPU_TRIMMED_VAL_2P4 (0x1 << 18) +#define OMAP4_DPLL_MPU_TRIMMED_VAL_3P0 (0x3 << 18) +#define OMAP4_DPLL_MPU_TRIMMED_MASK (BIT(19) | BIT(18)) +/* + * Trim value has to be written to CONTROL_EFUSE_2 according to + * OMAP4430 errata i684 (version B) + * OMAP4430 units with ProdID[51:50]=11 are not affected + */ +#define OMAP4_LPDDR2_I684_FIX_VALUE 0x004E4000 +#define OMAP4_PROD_ID_I684_MASK 0x000C0000 + + +static bool bgap_trim_sw_overide; +static bool dpll_trim_override; +static bool ddr_io_trim_override; + +/** + * omap4_ldo_trim_configure() - Handle device trim variance + * + * Few of the silicon out of the fab come out without trim parameters + * efused in. These need some software support to allow the device to + * function normally. Handle these silicon quirks here. + */ +int omap4_ldo_trim_configure(void) +{ + u32 val; + + /* if not trimmed, we set force overide, insted of efuse. */ + if (bgap_trim_sw_overide) { + /* Fill in recommended values */ + val = 0x0f << OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_SHIFT; + val |= OMAP4_LDOSRAMCORE_ACTMODE_MUX_CTRL_MASK; + val |= 0x1 << OMAP4_LDOSRAMCORE_RETMODE_VSET_OUT_SHIFT; + val |= OMAP4_LDOSRAMCORE_RETMODE_MUX_CTRL_MASK; + + omap_ctrl_writel(val, + OMAP4_CTRL_MODULE_CORE_LDOSRAM_MPU_VOLTAGE_CTRL); + omap_ctrl_writel(val, + OMAP4_CTRL_MODULE_CORE_LDOSRAM_CORE_VOLTAGE_CTRL); + omap_ctrl_writel(val, + OMAP4_CTRL_MODULE_CORE_LDOSRAM_IVA_VOLTAGE_CTRL); + } + + /* For all trimmed and untrimmed write value as per recomendation */ + val = 0x10 << OMAP4_AVDAC_TRIM_BYTE0_SHIFT; + val |= 0x01 << OMAP4_AVDAC_TRIM_BYTE1_SHIFT; + val |= 0x4d << OMAP4_AVDAC_TRIM_BYTE2_SHIFT; + val |= 0x1C << OMAP4_AVDAC_TRIM_BYTE3_SHIFT; + omap4_ctrl_pad_writel(val, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_1); + + /* DDR I/O Trim override as per erratum i684 */ + if (ddr_io_trim_override) { + omap4_ctrl_pad_writel(OMAP4_LPDDR2_I684_FIX_VALUE, + OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_2); + } + + /* Required for DPLL_MPU to lock at 2.4 GHz */ + if (dpll_trim_override) + omap_ctrl_writel(0x29, OMAP4_CTRL_MODULE_CORE_DPLL_NWELL_TRIM_0); + + return 0; +} + +/** + * omap4460_mpu_dpll_trim_override() - provide a selective s/w trim overide + */ +static __init void omap4460_mpu_dpll_trim_override(void) +{ + u32 val; + + val = omap_ctrl_readl(OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_DPLL_1) & + OMAP4_DPLL_MPU_TRIMMED_MASK; + switch (val) { + case OMAP4_DPLL_MPU_TRIMMED_VAL_3P0: + /* all ok.. */ + break; + case OMAP4_DPLL_MPU_TRIMMED_VAL_2P4: + /* Cross check! */ + if (omap4_has_mpu_1_5ghz()) { + WARN(1, "%s: OMAP is 1.5GHz capable, trimmed=1.2GHz!\n", + __func__); + } + break; + default: + WARN(1, "%s: UNKNOWN TRIM:0x%08x, using s/w override\n", + __func__, val); + /* fall through and use override */ + case 0: + /* + * For PRE_RTP devices: Not trimmed, use s/w override! + * We only support unto 1.2GHz with s/w override, + * so just give a gentle warning if higher opp is attempted + */ + dpll_trim_override = true; + /* Confirm */ + if (omap4_has_mpu_1_5ghz()) { + pr_err("%s: OMAP is 1.5GHz capable, s/w trim=1.2GHz!\n", + __func__); + } + break; + } +} + +static __init int omap4_ldo_trim_init(void) +{ + u32 bgap_trimmed = 0; + + /* Applicable only for OMAP4 */ + if (!cpu_is_omap44xx()) + return 0; + + /* + * Some ES2.2 efuse values for BGAP and SLDO trim + * are not programmed. For these units + * 1. we can set overide mode for SLDO trim, + * and program the max multiplication factor, to ensure + * high enough voltage on SLDO output. + * 2. trim VDAC value for TV output as per recomendation + */ + if (omap_rev() >= CHIP_IS_OMAP4430ES2_2) + bgap_trimmed = omap_ctrl_readl( + OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_BGAP); + + bgap_trimmed &= OMAP4_STD_FUSE_OPP_BGAP_MASK_LSB; + + /* if not trimmed, we set force overide, insted of efuse. */ + if (!bgap_trimmed) + bgap_trim_sw_overide = true; + + /* If not already trimmed, use s/w override */ + if (cpu_is_omap446x()) + omap4460_mpu_dpll_trim_override(); + + /* + * Errata i684 (revision B) + * Impacts all OMAP4430ESx.y trimmed and untrimmed excluding units + * with with ProdID[51:50]=11 + * OMAP4460/70 are not impacted. + * + * ProdID: + * 51 50 + * 0 0 Incorrect trim, SW WA needed. + * 0 1 Fixed test program issue of overlapping of LPDDR & SmartIO + * efuse fields, SW WA needed for LPDDR. + * 1 1 New LPDDR trim formula to compensate for vertical vs horizontal + * cell layout. No overwrite required. + */ + if (cpu_is_omap443x()) { + u32 prod_id; + + prod_id = omap_ctrl_readl( + OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_1); + prod_id &= OMAP4_PROD_ID_I684_MASK; + if (prod_id != OMAP4_PROD_ID_I684_MASK) + ddr_io_trim_override = true; + } + + return omap4_ldo_trim_configure(); +} +arch_initcall(omap4_ldo_trim_init); diff --git a/arch/arm/mach-omap2/omap_dmm.c b/arch/arm/mach-omap2/omap_dmm.c new file mode 100644 index 0000000..c2c44d2 --- /dev/null +++ b/arch/arm/mach-omap2/omap_dmm.c @@ -0,0 +1,73 @@ +/* + * DMM driver support functions for TI OMAP processors. + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/io.h> +#include <linux/init.h> +#include <linux/module.h> +#include <mach/dmm.h> +#include <plat/omap_device.h> +#include <plat/omap_hwmod.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <mach/dmm.h> +#include <mach/tiler.h> + +#ifdef CONFIG_TI_TILER + +static struct omap_dmm_platform_data dmm_data = { + .oh_name = "dmm", +}; + +static struct platform_device omap_tiler_device = { + .name = "tiler", + .id = -1, +}; + +static struct omap_device_pm_latency omap_dmm_latency[] = { + [0] = { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + + +void __init omap_dmm_init(void) +{ + struct omap_hwmod *oh = NULL; + struct omap_device *od = NULL; + + oh = omap_hwmod_lookup(dmm_data.oh_name); + if (!oh) + return; + + dmm_data.base = omap_hwmod_get_mpu_rt_va(oh); + dmm_data.irq = oh->mpu_irqs[0].irq; + + od = omap_device_build(dmm_data.oh_name, -1, oh, &dmm_data, + sizeof(dmm_data), omap_dmm_latency, + ARRAY_SIZE(omap_dmm_latency), false); + + /* register tiler platform device to go along with the dmm device */ + if (platform_device_register(&omap_tiler_device) < 0) + printk(KERN_ERR "Unable to register OMAP Tiler device\n"); + + return; +} + +#else +void __init omap_dmm_init(void) +{ +} +#endif diff --git a/arch/arm/mach-omap2/omap_fiq_debugger.c b/arch/arm/mach-omap2/omap_fiq_debugger.c new file mode 100644 index 0000000..174bba0 --- /dev/null +++ b/arch/arm/mach-omap2/omap_fiq_debugger.c @@ -0,0 +1,418 @@ +/* + * Serial Debugger Interface for Omap + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/serial_reg.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/stacktrace.h> +#include <linux/uaccess.h> + +#include <plat/omap_device.h> +#include <plat/omap-pm.h> +#include <plat/omap-serial.h> + +#include <asm/fiq_debugger.h> + +#include <mach/omap_fiq_debugger.h> +#include <mach/system.h> + +#include "mux.h" + +struct omap_fiq_debugger { + struct fiq_debugger_pdata pdata; + struct platform_device *pdev; + void __iomem *debug_port_base; + bool suspended; + spinlock_t lock; + bool have_state; + + /* uart state */ + unsigned char lcr; + unsigned char fcr; + unsigned char efr; + unsigned char dll; + unsigned char dlh; + unsigned char mcr; + unsigned char ier; + unsigned char wer; +}; + +static struct omap_fiq_debugger *dbgs[OMAP_MAX_HSUART_PORTS]; + +static inline struct omap_fiq_debugger *get_dbg(struct platform_device *pdev) +{ + struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev); + return container_of(pdata, struct omap_fiq_debugger, pdata); +} + +static inline void omap_write(struct omap_fiq_debugger *dbg, + unsigned int val, unsigned int off) +{ + __raw_writel(val, dbg->debug_port_base + off * 4); +} + +static inline unsigned int omap_read(struct omap_fiq_debugger *dbg, + unsigned int off) +{ + return __raw_readl(dbg->debug_port_base + off * 4); +} + +static void debug_omap_port_enable(struct platform_device *pdev) +{ + pm_runtime_get_sync(&pdev->dev); +} + +static void debug_omap_port_disable(struct platform_device *pdev) +{ + struct omap_fiq_debugger *dbg = get_dbg(pdev); + unsigned long flags; + + spin_lock_irqsave(&dbg->lock, flags); + if (!dbg->suspended) { + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + } else { + pm_runtime_put_sync_suspend(&pdev->dev); + } + spin_unlock_irqrestore(&dbg->lock, flags); +} + +static int debug_omap_port_resume(struct platform_device *pdev) +{ + struct omap_fiq_debugger *dbg = get_dbg(pdev); + + dbg->suspended = false; + barrier(); + return 0; +} + +static int debug_omap_port_suspend(struct platform_device *pdev) +{ + struct omap_fiq_debugger *dbg = get_dbg(pdev); + unsigned long flags; + + /* this will force the device to be idle'd now, in case it was + * autosuspended but timer has not yet run out. + */ + spin_lock_irqsave(&dbg->lock, flags); + dbg->suspended = true; + pm_runtime_get_sync(&pdev->dev); + pm_runtime_put_sync_suspend(&pdev->dev); + spin_unlock_irqrestore(&dbg->lock, flags); + + return 0; +} + +/* mostly copied from drivers/tty/serial/omap-serial.c */ +static void omap_write_mdr1(struct omap_fiq_debugger *dbg, u8 mdr1) +{ + u8 timeout = 255; + + if (!(cpu_is_omap34xx() || cpu_is_omap44xx())) { + omap_write(dbg, UART_OMAP_MDR1_DISABLE, UART_OMAP_MDR1); + return; + } + + omap_write(dbg, mdr1, UART_OMAP_MDR1); + udelay(2); + omap_write(dbg, dbg->fcr | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR, + UART_FCR); + + /* + * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and + * TX_FIFO_E bit is 1. + */ + while (UART_LSR_THRE != + (omap_read(dbg, UART_LSR) & (UART_LSR_THRE | UART_LSR_DR))) { + timeout--; + if (!timeout) { + /* Should *never* happen. we warn and carry on */ + dev_crit(&dbg->pdev->dev, "Errata i202: timedout %x\n", + omap_read(dbg, UART_LSR)); + break; + } + udelay(1); + } +} + +/* assume the bootloader programmed us correctly */ +static void debug_port_read_state(struct omap_fiq_debugger *dbg) +{ + /* assume we're in operational mode when we are called */ + dbg->lcr = omap_read(dbg, UART_LCR); + + /* config mode A */ + omap_write(dbg, UART_LCR_CONF_MODE_A, UART_LCR); + dbg->mcr = omap_read(dbg, UART_MCR); + + /* config mode B */ + omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR); + dbg->efr = omap_read(dbg, UART_EFR); + dbg->dll = omap_read(dbg, UART_DLL); + dbg->dlh = omap_read(dbg, UART_DLM); + + /* back to operational */ + omap_write(dbg, dbg->lcr, UART_LCR); + + pr_debug("%s: lcr=%02x mcr=%02x efr=%02x dll=%02x dlh=%02x\n", + __func__, dbg->lcr, dbg->mcr, dbg->efr, dbg->dll, dbg->dlh); +} + +static void debug_port_restore(struct omap_fiq_debugger *dbg) +{ + omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR); /* Config B mode */ + omap_write(dbg, dbg->efr | UART_EFR_ECB, UART_EFR); + omap_write(dbg, 0x0, UART_LCR); /* Operational mode */ + omap_write(dbg, 0x0, UART_IER); + omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR); /* Config B mode */ + omap_write(dbg, 0, UART_DLL); + omap_write(dbg, 0, UART_DLM); + omap_write(dbg, UART_LCR_CONF_MODE_A, UART_LCR); + omap_write(dbg, dbg->mcr | UART_MCR_TCRTLR, UART_MCR); + omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR); + omap_write(dbg, 0, UART_TI752_TLR); + omap_write(dbg, 0, UART_SCR); + omap_write(dbg, dbg->efr, UART_EFR); + omap_write(dbg, UART_LCR_CONF_MODE_A, UART_LCR); + omap_write(dbg, dbg->fcr, UART_FCR); + omap_write(dbg, dbg->mcr, UART_MCR); + omap_write_mdr1(dbg, UART_OMAP_MDR1_DISABLE); + + omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR); + omap_write(dbg, dbg->efr | UART_EFR_ECB, UART_EFR); + omap_write(dbg, dbg->dll, UART_DLL); + omap_write(dbg, dbg->dlh, UART_DLM); + omap_write(dbg, 0, UART_LCR); + omap_write(dbg, dbg->ier, UART_IER); + omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR); + omap_write(dbg, dbg->efr, UART_EFR); + + /* will put us back to operational mode */ + omap_write(dbg, dbg->lcr, UART_LCR); + omap_write_mdr1(dbg, UART_OMAP_MDR1_16X_MODE); + + omap_write(dbg, dbg->wer, UART_OMAP_WER); +} + +u32 omap_debug_uart_resume_idle(void) +{ + int i; + u32 ret = 0; + + for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) { + struct omap_fiq_debugger *dbg = dbgs[i]; + struct omap_device *od; + + if (!dbg || !dbg->pdev) + continue; + + od = to_omap_device(dbg->pdev); + if (omap_hwmod_pad_get_wakeup_status(od->hwmods[0])) { + /* + * poke the uart and let it stay on long enough + * to process any further data. It's ok to use + * autosuspend here since this is on the resume path + * during the wakeup. We'll still go through a full + * resume cycle, so if we go back to suspend + * the suspended flag will properly get reset. + */ + pm_runtime_get_sync(&dbg->pdev->dev); + pm_runtime_mark_last_busy(&dbg->pdev->dev); + pm_runtime_put_autosuspend(&dbg->pdev->dev); + dev_dbg(&dbg->pdev->dev, "woke up from IO pad\n"); + ret++; + } + } + + return ret; +} + +static int debug_port_init(struct platform_device *pdev) +{ + struct omap_fiq_debugger *dbg = get_dbg(pdev); + + dbg->ier = UART_IER_RLSI | UART_IER_RDI; + dbg->fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_01; + dbg->wer = 0; + + device_init_wakeup(&pdev->dev, true); + + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, DEFAULT_AUTOSUSPEND_DELAY); + + pm_runtime_enable(&pdev->dev); + pm_runtime_irq_safe(&pdev->dev); + + omap_hwmod_idle(to_omap_device(pdev)->hwmods[0]); + debug_omap_port_enable(pdev); + debug_omap_port_disable(pdev); + + debug_omap_port_enable(pdev); + + if (device_may_wakeup(&pdev->dev)) + omap_hwmod_enable_wakeup(to_omap_device(pdev)->hwmods[0]); + + debug_port_read_state(dbg); + debug_port_restore(dbg); + + dbg->have_state = true; + + + debug_omap_port_disable(pdev); + return 0; +} + +static int debug_getc(struct platform_device *pdev) +{ + struct omap_fiq_debugger *dbg = get_dbg(pdev); + unsigned int lsr; + int ret = FIQ_DEBUGGER_NO_CHAR; + + lsr = omap_read(dbg, UART_LSR); + if (lsr & UART_LSR_BI) { + /* need to read RHR to clear the BI condition */ + omap_read(dbg, UART_RX); + ret = FIQ_DEBUGGER_BREAK; + } else if (lsr & UART_LSR_DR) { + ret = omap_read(dbg, UART_RX); + } + + return ret; +} + +static void debug_putc(struct platform_device *pdev, unsigned int c) +{ + struct omap_fiq_debugger *dbg = get_dbg(pdev); + + while (!(omap_read(dbg, UART_LSR) & UART_LSR_THRE)) + cpu_relax(); + + omap_write(dbg, c, UART_TX); +} + +static void debug_flush(struct platform_device *pdev) +{ + struct omap_fiq_debugger *dbg = get_dbg(pdev); + + while (!(omap_read(dbg, UART_LSR) & UART_LSR_TEMT)) + cpu_relax(); +} + +static int uart_idle_hwmod(struct omap_device *od) +{ + omap_hwmod_idle(od->hwmods[0]); + + return 0; +} + +static int uart_enable_hwmod(struct omap_device *od) +{ + struct platform_device *pdev = &od->pdev; + struct omap_fiq_debugger *dbg = get_dbg(pdev); + + omap_hwmod_enable(od->hwmods[0]); + if (omap_pm_was_context_lost(&pdev->dev) && dbg->have_state) { + debug_port_restore(dbg); + dev_dbg(&pdev->dev, "restoring lost context!\n"); + } + + return 0; +} + +static struct omap_device_pm_latency omap_uart_latency[] = { + { + .deactivate_func = uart_idle_hwmod, + .activate_func = uart_enable_hwmod, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +extern struct omap_hwmod *omap_uart_hwmod_lookup(int num); + +int __init omap_serial_debug_init(int id, bool is_fiq, bool is_high_prio_irq, + struct omap_device_pad *pads, int num_pads) +{ + struct omap_fiq_debugger *dbg; + struct omap_hwmod *oh; + struct omap_device *od; + int ret; + + if (id >= OMAP_MAX_HSUART_PORTS) + return -EINVAL; + if (dbgs[id]) + return -EBUSY; + + oh = omap_uart_hwmod_lookup(id); + if (!oh) + return -ENODEV; + + oh->mpu_irqs[0].name = "uart_irq"; + oh->mux = omap_hwmod_mux_init(pads, num_pads); + + dbg = kzalloc(sizeof(struct omap_fiq_debugger), GFP_KERNEL); + if (!dbg) { + pr_err("Failed to allocate for fiq debugger\n"); + return -ENOMEM; + } + + dbg->debug_port_base = ioremap(oh->slaves[0]->addr[0].pa_start, + PAGE_SIZE); + if (!dbg->debug_port_base) { + pr_err("Failed to ioremap for fiq debugger\n"); + ret = -ENOMEM; + goto err_ioremap; + } + + spin_lock_init(&dbg->lock); + + dbg->pdata.uart_init = debug_port_init; + dbg->pdata.uart_getc = debug_getc; + dbg->pdata.uart_putc = debug_putc; + dbg->pdata.uart_flush = debug_flush; + dbg->pdata.uart_enable = debug_omap_port_enable; + dbg->pdata.uart_disable = debug_omap_port_disable; + dbg->pdata.uart_dev_suspend = debug_omap_port_suspend; + dbg->pdata.uart_dev_resume = debug_omap_port_resume; + + od = omap_device_build("fiq_debugger", id, + oh, dbg, sizeof(*dbg), omap_uart_latency, + ARRAY_SIZE(omap_uart_latency), false); + if (IS_ERR(od)) { + pr_err("Could not build omap_device for fiq_debugger: %s\n", + oh->name); + ret = PTR_ERR(od); + goto err_dev_build; + } + + dbg->pdev = &od->pdev; + dbgs[id] = dbg; + + return 0; + +err_dev_build: + iounmap(dbg->debug_port_base); +err_ioremap: + kfree(dbg); + return ret; +} diff --git a/arch/arm/mach-omap2/omap_hsi.c b/arch/arm/mach-omap2/omap_hsi.c new file mode 100644 index 0000000..ce8fa54 --- /dev/null +++ b/arch/arm/mach-omap2/omap_hsi.c @@ -0,0 +1,426 @@ +/* + * arch/arm/mach-omap2/hsi.c + * + * HSI device definition + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Original Author: Sebastien JAN <s-jan@ti.com> + * + * This package 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. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/jiffies.h> +#include <linux/notifier.h> +#include <linux/hsi_driver_if.h> + +#include <asm/clkdev.h> + +#include <plat/omap_hsi.h> +#include <plat/omap_hwmod.h> +#include <plat/omap_device.h> + +#include <../drivers/omap_hsi/hsi_driver.h> +#include "clock.h" +#include "mux.h" +#include "control.h" + +static int omap_hsi_wakeup_enable(int hsi_port); +static int omap_hsi_wakeup_disable(int hsi_port); +#define OMAP_HSI_PLATFORM_DEVICE_DRIVER_NAME "omap_hsi" +#define OMAP_HSI_PLATFORM_DEVICE_NAME "omap_hsi.0" +#define OMAP_HSI_HWMOD_NAME "hsi" +#define OMAP_HSI_HWMOD_CLASSNAME "hsi" +#define OMAP_HSI_PADCONF_CAWAKE_PIN "usbb1_ulpitll_clk.hsi1_cawake" +#define OMAP_HSI_PADCONF_CAWAKE_MODE OMAP_MUX_MODE1 + + +#define OMAP_MUX_MODE_MASK 0x7 + + +/* Hack till correct hwmod-mux api gets used */ +#define CA_WAKE_MUX_REG (0x4a1000C2) +#define OMAP44XX_PADCONF_WAKEUPENABLE0 (1 << 14) +#define OMAP44XX_PADCONF_WAKEUPEVENT0 (1 << 15) + +static int omap_mux_read_signal(const char *muxname) +{ + u16 val = 0; + val = omap_readw(CA_WAKE_MUX_REG); + return val; +} + +static int omap_mux_enable_wakeup(const char *muxname) +{ + u16 val = 0; + val = omap_readw(CA_WAKE_MUX_REG); + val |= OMAP44XX_PADCONF_WAKEUPENABLE0; + omap_writew(val, CA_WAKE_MUX_REG); + return 0; +} + +static int omap_mux_disable_wakeup(const char *muxname) +{ + u16 val = 0; + val = omap_readw(CA_WAKE_MUX_REG); + val &= ~OMAP44XX_PADCONF_WAKEUPENABLE0; + omap_writew(val, CA_WAKE_MUX_REG); + return 0; +} + +/* + * NOTE: We abuse a little bit the struct port_ctx to use it also for + * initialization. + */ + + +static struct port_ctx hsi_port_ctx[] = { + [0] = { + .hst.mode = HSI_MODE_FRAME, + .hst.flow = HSI_FLOW_SYNCHRONIZED, + .hst.frame_size = HSI_FRAMESIZE_DEFAULT, + .hst.divisor = HSI_DIVISOR_DEFAULT, + .hst.channels = HSI_CHANNELS_DEFAULT, + .hst.arb_mode = HSI_ARBMODE_ROUNDROBIN, + .hsr.mode = HSI_MODE_FRAME, + .hsr.flow = HSI_FLOW_SYNCHRONIZED, + .hsr.frame_size = HSI_FRAMESIZE_DEFAULT, + .hsr.channels = HSI_CHANNELS_DEFAULT, + .hsr.divisor = HSI_DIVISOR_DEFAULT, + .hsr.counters = HSI_COUNTERS_FT_DEFAULT | + HSI_COUNTERS_TB_DEFAULT | + HSI_COUNTERS_FB_DEFAULT, + }, +}; + +static struct ctrl_ctx hsi_ctx = { + .sysconfig = 0, + .gdd_gcr = 0, + .dll = 0, + .pctx = hsi_port_ctx, +}; + +static struct hsi_platform_data omap_hsi_platform_data = { + .num_ports = ARRAY_SIZE(hsi_port_ctx), + .hsi_gdd_chan_count = HSI_HSI_DMA_CHANNEL_MAX, + .default_hsi_fclk = HSI_DEFAULT_FCLK, + .ctx = &hsi_ctx, + .device_enable = omap_device_enable, + .device_idle = omap_device_idle, + .device_shutdown = omap_device_shutdown, + .wakeup_enable = omap_hsi_wakeup_enable, + .wakeup_disable = omap_hsi_wakeup_disable, + .wakeup_is_from_hsi = omap_hsi_is_io_wakeup_from_hsi, + .board_suspend = omap_hsi_prepare_suspend, +}; + + +static struct platform_device *hsi_get_hsi_platform_device(void) +{ + struct device *dev; + struct platform_device *pdev; + + /* HSI_TODO: handle platform device id (or port) (0/1) */ + dev = bus_find_device_by_name(&platform_bus_type, NULL, + OMAP_HSI_PLATFORM_DEVICE_NAME); + if (!dev) { + pr_debug("Could not find platform device %s\n", + OMAP_HSI_PLATFORM_DEVICE_NAME); + return 0; + } + + if (!dev->driver) { + /* Could not find driver for platform device. */ + return 0; + } + + pdev = to_platform_device(dev); + + return pdev; +} + +static struct hsi_dev *hsi_get_hsi_controller_data(struct platform_device *pd) +{ + struct hsi_dev *hsi_ctrl; + + if (!pd) + return 0; + + hsi_ctrl = (struct hsi_dev *) platform_get_drvdata(pd); + if (!hsi_ctrl) { + pr_err("Could not find HSI controller data\n"); + return 0; + } + + return hsi_ctrl; +} + +/** +* omap_hsi_is_io_pad_hsi - Indicates if IO Pad has been muxed for HSI CAWAKE +* +* Return value :* 0 if CAWAKE Padconf has not been found or CAWAKE not muxed for +* CAWAKE +* * else 1 +*/ +static int omap_hsi_is_io_pad_hsi(void) +{ + u16 val; + + /* Check for IO pad */ + val = omap_mux_read_signal(OMAP_HSI_PADCONF_CAWAKE_PIN); + if (val == -ENODEV) + return 0; + + /* Continue only if CAWAKE is muxed */ + if ((val & OMAP_MUX_MODE_MASK) != OMAP_HSI_PADCONF_CAWAKE_MODE) + return 0; + + return 1; +} + +/** +* omap_hsi_is_io_wakeup_from_hsi - Indicates an IO wakeup from HSI CAWAKE +* +* Return value :* 0 if CAWAKE Padconf has not been found or no IOWAKEUP event +* occured for CAWAKE +* * else 1 +* TODO : return value should indicate the HSI port which has awaken +*/ +int omap_hsi_is_io_wakeup_from_hsi(void) +{ + u16 val; + + /* Check for IO pad wakeup */ + val = omap_mux_read_signal(OMAP_HSI_PADCONF_CAWAKE_PIN); + if (val == -ENODEV) + return 0; + + /* Continue only if CAWAKE is muxed */ + if ((val & OMAP_MUX_MODE_MASK) != OMAP_HSI_PADCONF_CAWAKE_MODE) + return 0; + + if (val & OMAP44XX_PADCONF_WAKEUPEVENT0) + return 1; + + return 0; +} + +/** +* omap_hsi_wakeup_enable - Enable HSI wakeup feature from RET/OFF mode +* +* @hsi_port - reference to the HSI port onto which enable wakeup feature. +* +* Return value :* 0 if CAWAKE has been configured to wakeup platform +* * -ENODEV if CAWAKE is not muxed on padconf +*/ +static int omap_hsi_wakeup_enable(int hsi_port) +{ + int ret = -ENODEV; + + if (omap_hsi_is_io_pad_hsi()) + ret = omap_mux_enable_wakeup(OMAP_HSI_PADCONF_CAWAKE_PIN); + else + pr_debug("Trying to enable HSI IO wakeup on non HSI board\n"); + + + /* TODO: handle hsi_port param and use it to find the correct Pad */ + return ret; +} + +/** +* omap_hsi_wakeup_disable - Disable HSI wakeup feature from RET/OFF mode +* +* @hsi_port - reference to the HSI port onto which disable wakeup feature. +* +* Return value :* 0 if CAWAKE has been configured to not wakeup platform +* * -ENODEV if CAWAKE is not muxed on padconf +*/ +static int omap_hsi_wakeup_disable(int hsi_port) +{ + int ret = -ENODEV; + + if (omap_hsi_is_io_pad_hsi()) + ret = omap_mux_disable_wakeup(OMAP_HSI_PADCONF_CAWAKE_PIN); + else + pr_debug("Trying to disable HSI IO wakeup on non HSI board\n"); + + + /* TODO: handle hsi_port param and use it to find the correct Pad */ + + return ret; +} + +/** +* omap_hsi_prepare_suspend - Prepare HSI for suspend mode +* +* Return value :* 0 if CAWAKE padconf has been configured properly +* * -ENODEV if CAWAKE is not muxed on padconf. +* +*/ +int omap_hsi_prepare_suspend(int hsi_port, bool dev_may_wakeup) +{ + int ret; + + if (dev_may_wakeup) + ret = omap_hsi_wakeup_enable(hsi_port); + else + ret = omap_hsi_wakeup_disable(hsi_port); + + return ret; +} + +/** +* omap_hsi_wakeup - Prepare HSI for wakeup from suspend mode (RET/OFF) +* +* Return value : 1 if IO wakeup source is HSI +* 0 if IO wakeup source is not HSI. +*/ +int omap_hsi_wakeup(int hsi_port) +{ + static struct platform_device *pdev; + static struct hsi_dev *hsi_ctrl; + + if (!pdev) { + pdev = hsi_get_hsi_platform_device(); + if (!pdev) + return -ENODEV; +} + + if (!device_may_wakeup(&pdev->dev)) { + dev_info(&pdev->dev, "Modem not allowed to wakeup platform"); + return -EPERM; + } + + if (!hsi_ctrl) { + hsi_ctrl = hsi_get_hsi_controller_data(pdev); + if (!hsi_ctrl) + return -ENODEV; + } + + dev_dbg(hsi_ctrl->dev, "Modem wakeup detected from HSI CAWAKE Pad"); + + /* CAWAKE falling or rising edge detected */ + hsi_ctrl->hsi_port->cawake_off_event = true; + tasklet_hi_schedule(&hsi_ctrl->hsi_port->hsi_tasklet); + + /* Disable interrupt until Bottom Half has cleared */ + /* the IRQ status register */ + disable_irq_nosync(hsi_ctrl->hsi_port->irq); + + return 0; +} + +/* HSI_TODO : This requires some fine tuning & completion of + * activate/deactivate latency values + */ +static struct omap_device_pm_latency omap_hsi_latency[] = { + [0] = { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +/* HSI device registration */ +static int __init omap_hsi_register(struct omap_hwmod *oh, void *user) +{ + struct omap_device *od; + struct hsi_platform_data *pdata = &omap_hsi_platform_data; + + if (!oh) { + pr_err("Could not look up %s omap_hwmod\n", + OMAP_HSI_HWMOD_NAME); + return -EEXIST; + } + + od = omap_device_build(OMAP_HSI_PLATFORM_DEVICE_DRIVER_NAME, 0, oh, + pdata, sizeof(*pdata), omap_hsi_latency, + ARRAY_SIZE(omap_hsi_latency), false); + WARN(IS_ERR(od), "Can't build omap_device for %s:%s.\n", + OMAP_HSI_PLATFORM_DEVICE_DRIVER_NAME, oh->name); + + pr_info("HSI: device registered as omap_hwmod: %s\n", oh->name); + return 0; +} + +static void __init omap_4430hsi_pad_conf(void) +{ + /* + * HSI pad conf: hsi1_ca/ac_wake/flag/data/ready + * Also configure gpio_92/95/157/187 used by modem + */ + /* hsi1_cawake */ + omap_mux_init_signal("usbb1_ulpitll_clk.hsi1_cawake", \ + OMAP_PIN_INPUT_PULLDOWN | \ + OMAP_PIN_OFF_NONE | \ + OMAP_PIN_OFF_WAKEUPENABLE); + /* hsi1_caflag */ + omap_mux_init_signal("usbb1_ulpitll_dir.hsi1_caflag", \ + OMAP_PIN_INPUT | \ + OMAP_PIN_OFF_NONE); + /* hsi1_cadata */ + omap_mux_init_signal("usbb1_ulpitll_stp.hsi1_cadata", \ + OMAP_PIN_INPUT | \ + OMAP_PIN_OFF_NONE); + /* hsi1_acready */ + omap_mux_init_signal("usbb1_ulpitll_nxt.hsi1_acready", \ + OMAP_PIN_OUTPUT | \ + OMAP_PIN_OFF_OUTPUT_LOW); + /* hsi1_acwake */ + omap_mux_init_signal("usbb1_ulpitll_dat0.hsi1_acwake", \ + OMAP_PIN_OUTPUT | \ + OMAP_PIN_OFF_NONE); + /* hsi1_acdata */ + omap_mux_init_signal("usbb1_ulpitll_dat1.hsi1_acdata", \ + OMAP_PIN_OUTPUT | \ + OMAP_PIN_OFF_NONE); + /* hsi1_acflag */ + omap_mux_init_signal("usbb1_ulpitll_dat2.hsi1_acflag", \ + OMAP_PIN_OUTPUT | \ + OMAP_PIN_OFF_NONE); + /* hsi1_caready */ + omap_mux_init_signal("usbb1_ulpitll_dat3.hsi1_caready", \ + OMAP_PIN_INPUT | \ + OMAP_PIN_OFF_NONE); + /* gpio_92 */ + omap_mux_init_signal("usbb1_ulpitll_dat4.gpio_92", \ + OMAP_PULL_ENA); + /* gpio_95 */ + omap_mux_init_signal("usbb1_ulpitll_dat7.gpio_95", \ + OMAP_PIN_INPUT_PULLDOWN | \ + OMAP_PIN_OFF_NONE); + /* gpio_157 */ + omap_mux_init_signal("usbb2_ulpitll_clk.gpio_157", \ + OMAP_PIN_OUTPUT | \ + OMAP_PIN_OFF_NONE); + /* gpio_187 */ + omap_mux_init_signal("sys_boot3.gpio_187", \ + OMAP_PIN_OUTPUT | \ + OMAP_PIN_OFF_NONE); +} + +int __init omap_hsi_dev_init(void) +{ + /* Keep this for genericity, although there is only one hwmod for HSI */ + return omap_hwmod_for_each_by_class(OMAP_HSI_HWMOD_CLASSNAME, + omap_hsi_register, NULL); +} +postcore_initcall(omap_hsi_dev_init); + +/* HSI devices registration */ +int __init omap_hsi_init(void) +{ + omap_4430hsi_pad_conf(); + return 0; +} diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 293fa6c..fac4aec 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -142,13 +142,16 @@ #include "powerdomain.h" #include <plat/clock.h> #include <plat/omap_hwmod.h> +#include <plat/omap_device.h> #include <plat/prcm.h> +#include <mach/emif.h> #include "cm2xxx_3xxx.h" #include "cm44xx.h" #include "prm2xxx_3xxx.h" #include "prm44xx.h" #include "mux.h" +#include "pm.h" /* Maximum microseconds to wait for OMAP module to softreset */ #define MAX_MODULE_SOFTRESET_WAIT 10000 @@ -391,7 +394,8 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) if (!oh->class->sysc || !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || - (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) + (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || + (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP))) return -EINVAL; if (!oh->class->sysc->sysc_fields) { @@ -401,10 +405,13 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); - *v |= wakeup_mask; + if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) + *v |= wakeup_mask; if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ @@ -426,7 +433,8 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) if (!oh->class->sysc || !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || - (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) + (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || + (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP))) return -EINVAL; if (!oh->class->sysc->sysc_fields) { @@ -436,10 +444,13 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); - *v &= ~wakeup_mask; + if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) + *v &= ~wakeup_mask; if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); /* XXX test pwrdm_get_wken for this hwmod's subsystem */ @@ -781,8 +792,16 @@ static void _enable_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? - HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; + if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + idlemode = HWMOD_IDLEMODE_NO; + } else { + if (sf & SYSC_HAS_ENAWAKEUP) + _enable_wakeup(oh, &v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + idlemode = HWMOD_IDLEMODE_SMART_WKUP; + else + idlemode = HWMOD_IDLEMODE_SMART; + } _set_master_standbymode(oh, idlemode, &v); } @@ -840,8 +859,16 @@ static void _idle_sysc(struct omap_hwmod *oh) } if (sf & SYSC_HAS_MIDLEMODE) { - idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? - HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART; + if (oh->flags & HWMOD_SWSUP_MSTANDBY) { + idlemode = HWMOD_IDLEMODE_FORCE; + } else { + if (sf & SYSC_HAS_ENAWAKEUP) + _enable_wakeup(oh, &v); + if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) + idlemode = HWMOD_IDLEMODE_SMART_WKUP; + else + idlemode = HWMOD_IDLEMODE_SMART; + } _set_master_standbymode(oh, idlemode, &v); } @@ -1154,6 +1181,9 @@ static int _ocp_softreset(struct omap_hwmod *oh) goto dis_opt_clks; _write_sysconfig(v, oh); + if (oh->class->sysc->srst_udelay) + udelay(oh->class->sysc->srst_udelay); + if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS) omap_test_timeout((omap_hwmod_read(oh, oh->class->sysc->syss_offs) @@ -1223,6 +1253,7 @@ static int _reset(struct omap_hwmod *oh) static int _enable(struct omap_hwmod *oh) { int r; + int hwsup = 0; if (oh->_state != _HWMOD_STATE_INITIALIZED && oh->_state != _HWMOD_STATE_IDLE && @@ -1243,17 +1274,17 @@ static int _enable(struct omap_hwmod *oh) oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) _deassert_hardreset(oh, oh->rst_lines[0].name); - /* Mux pins for device runtime if populated */ - if (oh->mux && (!oh->mux->enabled || - ((oh->_state == _HWMOD_STATE_IDLE) && - oh->mux->pads_dynamic))) - omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); - _add_initiator_dep(oh, mpu_oh); + if (oh->_clk && oh->_clk->clkdm) { + hwsup = clkdm_is_idle(oh->_clk->clkdm); + clkdm_wakeup(oh->_clk->clkdm); + } _enable_clocks(oh); - r = _wait_target_ready(oh); if (!r) { + if (oh->_clk && oh->_clk->clkdm && hwsup) + clkdm_allow_idle(oh->_clk->clkdm); + oh->_state = _HWMOD_STATE_ENABLED; /* Access the sysconfig only if the target is ready */ @@ -1268,6 +1299,12 @@ static int _enable(struct omap_hwmod *oh) oh->name, r); } + /* Mux pins for device runtime if populated */ + if (oh->mux && (!oh->mux->enabled || + ((oh->_state == _HWMOD_STATE_ENABLED) && + oh->mux->pads_dynamic))) + omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); + return r; } @@ -1295,8 +1332,11 @@ static int _idle(struct omap_hwmod *oh) _disable_clocks(oh); /* Mux pins for device idle if populated */ - if (oh->mux && oh->mux->pads_dynamic) + if (oh->mux && oh->mux->pads_dynamic) { omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); + if (cpu_is_omap44xx()) + omap4_trigger_ioctrl(); + } oh->_state = _HWMOD_STATE_IDLE; @@ -1374,8 +1414,11 @@ static int _shutdown(struct omap_hwmod *oh) } } - if (oh->class->sysc) + if (oh->class->sysc) { + if (oh->_state == _HWMOD_STATE_IDLE) + _enable(oh); _shutdown_sysc(oh); + } /* * If an IP contains only one HW reset line, then assert it @@ -1507,6 +1550,7 @@ static int _setup(struct omap_hwmod *oh, void *data) * that the copy process would be relatively complex due to the large number * of substructures. */ + static int __init _register(struct omap_hwmod *oh) { int ms_id; @@ -1538,6 +1582,12 @@ static int __init _register(struct omap_hwmod *oh) */ if (!strcmp(oh->name, MPU_INITIATOR_NAME)) mpu_oh = oh; + else if (cpu_is_omap44xx()) { + if (!strcmp(oh->name, "emif1")) + emif_clear_irq(0); + else if (!strcmp(oh->name, "emif2")) + emif_clear_irq(1); + } return 0; } @@ -1770,6 +1820,34 @@ static int __init omap_hwmod_setup_all(void) core_initcall(omap_hwmod_setup_all); /** + * omap_hwmod_set_ioring_wakeup - enable io pad wakeup flag. + * @oh: struct omap_hwmod * + * @set: bool value indicating to set or clear wakeup status. + * + * Set or Clear wakeup flag for the io_pad. + */ +static int omap_hwmod_set_ioring_wakeup(struct omap_hwmod *oh, bool set_wake) +{ + struct omap_device_pad *pad; + int ret = -EINVAL, j; + + if (oh->mux && oh->mux->enabled) { + for (j = 0; j < oh->mux->nr_pads_dynamic; j++) { + pad = oh->mux->pads_dynamic[j]; + if (pad->flags & OMAP_DEVICE_PAD_WAKEUP) { + if (set_wake) + pad->idle |= OMAP_WAKEUP_EN; + else + pad->idle &= ~OMAP_WAKEUP_EN; + ret = 0; + } + } + } + + return ret; +} + +/** * omap_hwmod_enable - enable an omap_hwmod * @oh: struct omap_hwmod * * @@ -2097,6 +2175,35 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh, { return _del_initiator_dep(oh, init_oh); } +/** + * omap_hwmod_enable_ioring_wakeup - Set wakeup flag for iopad. + * @oh: struct omap_hwmod * + * + * Traverse through dynamic pads, if pad is enabled then + * set wakeup enable bit flag for the mux pin. Wakeup pad bit + * will be set during hwmod idle transistion. + * Return error if pads are not enabled or not available. + */ +int omap_hwmod_enable_ioring_wakeup(struct omap_hwmod *oh) +{ + /* Enable pad wake-up capability */ + return omap_hwmod_set_ioring_wakeup(oh, true); +} + +/** + * omap_hwmod_disable_ioring_wakeup - Clear wakeup flag for iopad. + * @oh: struct omap_hwmod * + * + * Traverse through dynamic pads, if pad is enabled then + * clear wakeup enable bit flag for the mux pin. Wakeup pad bit + * will be set during hwmod idle transistion. + * Return error if pads are not enabled or not available. + */ +int omap_hwmod_disable_ioring_wakeup(struct omap_hwmod *oh) +{ + /* Disable pad wakeup capability */ + return omap_hwmod_set_ioring_wakeup(oh, false); +} /** * omap_hwmod_enable_wakeup - allow device to wake up the system @@ -2123,6 +2230,7 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) v = oh->_sysc_cache; _enable_wakeup(oh, &v); _write_sysconfig(v, oh); + omap_hwmod_enable_ioring_wakeup(oh); spin_unlock_irqrestore(&oh->_lock, flags); return 0; @@ -2153,6 +2261,7 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) v = oh->_sysc_cache; _disable_wakeup(oh, &v); _write_sysconfig(v, oh); + omap_hwmod_disable_ioring_wakeup(oh); spin_unlock_irqrestore(&oh->_lock, flags); return 0; @@ -2332,7 +2441,7 @@ ohsps_unlock: * Returns the context loss count of the powerdomain assocated with @oh * upon success, or zero if no powerdomain exists for @oh. */ -u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) +int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) { struct powerdomain *pwrdm; int ret = 0; @@ -2369,3 +2478,42 @@ int omap_hwmod_no_setup_reset(struct omap_hwmod *oh) return 0; } + +int omap_hwmod_pad_get_wakeup_status(struct omap_hwmod *oh) +{ + if (oh && oh->mux) + return omap_hwmod_mux_get_wake_status(oh->mux); + return -EINVAL; +} + +/** + * omap_hwmod_name_get_dev() - convert a hwmod name to device pointer + * @oh_name: name of the hwmod device + * + * returns back a struct device * pointer associated with a hwmod + * device represented by a hwmod_name + */ +struct device *omap_hwmod_name_get_dev(const char *oh_name) +{ + struct omap_hwmod *oh; + + if (!oh_name) { + WARN(1, "%s: no hwmod name!\n", __func__); + return ERR_PTR(-EINVAL); + } + + oh = _lookup(oh_name); + if (IS_ERR_OR_NULL(oh)) { + WARN(1, "%s: no hwmod for %s\n", __func__, + oh_name); + return ERR_PTR(oh ? PTR_ERR(oh) : -ENODEV); + } + if (IS_ERR_OR_NULL(oh->od)) { + WARN(1, "%s: no omap_device for %s\n", __func__, + oh_name); + return ERR_PTR(oh ? PTR_ERR(oh) : -ENODEV); + } + + return &oh->od->pdev.dev; +} +EXPORT_SYMBOL(omap_hwmod_name_get_dev); diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index c4d0ae8..d87019d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -1208,6 +1208,7 @@ static struct omap_hwmod_ocp_if *omap2420_dss_slaves[] = { }; static struct omap_hwmod_opt_clk dss_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_fck" }, { .role = "tv_clk", .clk = "dss_54m_fck" }, { .role = "sys_clk", .clk = "dss2_fck" }, }; @@ -1291,6 +1292,10 @@ static struct omap_hwmod_ocp_if *omap2420_dss_dispc_slaves[] = { &omap2420_l4_core__dss_dispc, }; +static struct omap_hwmod_opt_clk dispc_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_fck" }, +}; + static struct omap_hwmod omap2420_dss_dispc_hwmod = { .name = "dss_dispc", .class = &omap2420_dispc_hwmod_class, @@ -1306,6 +1311,8 @@ static struct omap_hwmod omap2420_dss_dispc_hwmod = { .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT, }, }, + .opt_clks = dispc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dispc_opt_clks), .slaves = omap2420_dss_dispc_slaves, .slaves_cnt = ARRAY_SIZE(omap2420_dss_dispc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), @@ -1361,6 +1368,10 @@ static struct omap_hwmod_ocp_if *omap2420_dss_rfbi_slaves[] = { &omap2420_l4_core__dss_rfbi, }; +static struct omap_hwmod_opt_clk rfbi_opt_clks[] = { + { .role = "rfbi_iclk", .clk = "dss_ick" }, +}; + static struct omap_hwmod omap2420_dss_rfbi_hwmod = { .name = "dss_rfbi", .class = &omap2420_rfbi_hwmod_class, @@ -1372,6 +1383,8 @@ static struct omap_hwmod omap2420_dss_rfbi_hwmod = { .module_offs = CORE_MOD, }, }, + .opt_clks = rfbi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(rfbi_opt_clks), .slaves = omap2420_dss_rfbi_slaves, .slaves_cnt = ARRAY_SIZE(omap2420_dss_rfbi_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), @@ -1418,6 +1431,10 @@ static struct omap_hwmod_ocp_if *omap2420_dss_venc_slaves[] = { &omap2420_l4_core__dss_venc, }; +static struct omap_hwmod_opt_clk venc_opt_clks[] = { + { .role = "tv_clk", .clk = "dss_54m_fck" }, +}; + static struct omap_hwmod omap2420_dss_venc_hwmod = { .name = "dss_venc", .class = &omap2420_venc_hwmod_class, @@ -1429,6 +1446,8 @@ static struct omap_hwmod omap2420_dss_venc_hwmod = { .module_offs = CORE_MOD, }, }, + .opt_clks = venc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(venc_opt_clks), .slaves = omap2420_dss_venc_slaves, .slaves_cnt = ARRAY_SIZE(omap2420_dss_venc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index 9682dd5..8009945 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -1302,6 +1302,7 @@ static struct omap_hwmod_ocp_if *omap2430_dss_slaves[] = { }; static struct omap_hwmod_opt_clk dss_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_fck" }, { .role = "tv_clk", .clk = "dss_54m_fck" }, { .role = "sys_clk", .clk = "dss2_fck" }, }; @@ -1379,6 +1380,10 @@ static struct omap_hwmod_ocp_if *omap2430_dss_dispc_slaves[] = { &omap2430_l4_core__dss_dispc, }; +static struct omap_hwmod_opt_clk dispc_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_fck" }, +}; + static struct omap_hwmod omap2430_dss_dispc_hwmod = { .name = "dss_dispc", .class = &omap2430_dispc_hwmod_class, @@ -1394,6 +1399,8 @@ static struct omap_hwmod omap2430_dss_dispc_hwmod = { .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT, }, }, + .opt_clks = dispc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dispc_opt_clks), .slaves = omap2430_dss_dispc_slaves, .slaves_cnt = ARRAY_SIZE(omap2430_dss_dispc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), @@ -1443,6 +1450,10 @@ static struct omap_hwmod_ocp_if *omap2430_dss_rfbi_slaves[] = { &omap2430_l4_core__dss_rfbi, }; +static struct omap_hwmod_opt_clk rfbi_opt_clks[] = { + { .role = "rfbi_iclk", .clk = "dss_ick" }, +}; + static struct omap_hwmod omap2430_dss_rfbi_hwmod = { .name = "dss_rfbi", .class = &omap2430_rfbi_hwmod_class, @@ -1454,6 +1465,8 @@ static struct omap_hwmod omap2430_dss_rfbi_hwmod = { .module_offs = CORE_MOD, }, }, + .opt_clks = rfbi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(rfbi_opt_clks), .slaves = omap2430_dss_rfbi_slaves, .slaves_cnt = ARRAY_SIZE(omap2430_dss_rfbi_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), @@ -1494,6 +1507,10 @@ static struct omap_hwmod_ocp_if *omap2430_dss_venc_slaves[] = { &omap2430_l4_core__dss_venc, }; +static struct omap_hwmod_opt_clk venc_opt_clks[] = { + { .role = "tv_clk", .clk = "dss_54m_fck" }, +}; + static struct omap_hwmod omap2430_dss_venc_hwmod = { .name = "dss_venc", .class = &omap2430_venc_hwmod_class, @@ -1505,6 +1522,8 @@ static struct omap_hwmod omap2430_dss_venc_hwmod = { .module_offs = CORE_MOD, }, }, + .opt_clks = venc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(venc_opt_clks), .slaves = omap2430_dss_venc_slaves, .slaves_cnt = ARRAY_SIZE(omap2430_dss_venc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 909a84d..b327776 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -29,6 +29,7 @@ #include "omap_hwmod_common_data.h" +#include "smartreflex.h" #include "prm-regbits-34xx.h" #include "cm-regbits-34xx.h" #include "wd_timer.h" @@ -84,6 +85,10 @@ static struct omap_hwmod omap3xxx_mcbsp4_hwmod; static struct omap_hwmod omap3xxx_mcbsp5_hwmod; static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod; static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod; +static struct omap_hwmod omap34xx_usb_host_hs_hwmod; +static struct omap_hwmod omap34xx_usbhs_ohci_hwmod; +static struct omap_hwmod omap34xx_usbhs_ehci_hwmod; +static struct omap_hwmod omap34xx_usb_tll_hs_hwmod; /* L3 -> L4_CORE interface */ static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = { @@ -396,6 +401,15 @@ static struct omap_hwmod_ocp_if omap3_l4_core__i2c3 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; + +static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = { + {.name = "sr1_irq", .irq = 18}, +}; + +static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = { + {.name = "sr2_irq", .irq = 19}, +}; + /* L4 CORE -> SR1 interface */ static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = { { @@ -1542,9 +1556,15 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_slaves[] = { }; static struct omap_hwmod_opt_clk dss_opt_clks[] = { - { .role = "tv_clk", .clk = "dss_tv_fck" }, - { .role = "video_clk", .clk = "dss_96m_fck" }, + { .role = "dss_clk", .clk = "dss1_alwon_fck" }, + /* + * The rest of the clocks are not needed by the driver, + * but are needed by the hwmod to reset DSS properly. + */ { .role = "sys_clk", .clk = "dss2_alwon_fck" }, + { .role = "tv_clk", .clk = "dss_tv_fck" }, + /* required only on OMAP3430 */ + { .role = "tv_dac_clk", .clk = "dss_96m_fck" }, }; static struct omap_hwmod omap3430es1_dss_core_hwmod = { @@ -1656,6 +1676,10 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_dispc_slaves[] = { &omap3xxx_l4_core__dss_dispc, }; +static struct omap_hwmod_opt_clk dispc_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_alwon_fck" }, +}; + static struct omap_hwmod omap3xxx_dss_dispc_hwmod = { .name = "dss_dispc", .class = &omap3xxx_dispc_hwmod_class, @@ -1669,6 +1693,8 @@ static struct omap_hwmod omap3xxx_dss_dispc_hwmod = { .module_offs = OMAP3430_DSS_MOD, }, }, + .opt_clks = dispc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dispc_opt_clks), .slaves = omap3xxx_dss_dispc_slaves, .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_dispc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | @@ -1720,6 +1746,11 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_dsi1_slaves[] = { &omap3xxx_l4_core__dss_dsi1, }; +static struct omap_hwmod_opt_clk dsi1_opt_clks[] = { + { .role = "dss_clk", .clk = "dss1_alwon_fck" }, + { .role = "sys_clk", .clk = "dss2_alwon_fck" }, +}; + static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = { .name = "dss_dsi1", .class = &omap3xxx_dsi_hwmod_class, @@ -1733,6 +1764,8 @@ static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = { .module_offs = OMAP3430_DSS_MOD, }, }, + .opt_clks = dsi1_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dsi1_opt_clks), .slaves = omap3xxx_dss_dsi1_slaves, .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_dsi1_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | @@ -1791,6 +1824,10 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_rfbi_slaves[] = { &omap3xxx_l4_core__dss_rfbi, }; +static struct omap_hwmod_opt_clk rfbi_opt_clks[] = { + { .role = "rfbi_iclk", .clk = "dss_ick" }, +}; + static struct omap_hwmod omap3xxx_dss_rfbi_hwmod = { .name = "dss_rfbi", .class = &omap3xxx_rfbi_hwmod_class, @@ -1802,6 +1839,8 @@ static struct omap_hwmod omap3xxx_dss_rfbi_hwmod = { .module_offs = OMAP3430_DSS_MOD, }, }, + .opt_clks = rfbi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(rfbi_opt_clks), .slaves = omap3xxx_dss_rfbi_slaves, .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_rfbi_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | @@ -1851,6 +1890,12 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_venc_slaves[] = { &omap3xxx_l4_core__dss_venc, }; +static struct omap_hwmod_opt_clk venc_opt_clks[] = { + { .role = "tv_clk", .clk = "dss_tv_fck" }, + /* required only on OMAP3430 */ + { .role = "tv_dac_clk", .clk = "dss_96m_fck" }, +}; + static struct omap_hwmod omap3xxx_dss_venc_hwmod = { .name = "dss_venc", .class = &omap3xxx_venc_hwmod_class, @@ -1862,6 +1907,8 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = { .module_offs = OMAP3430_DSS_MOD, }, }, + .opt_clks = venc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(venc_opt_clks), .slaves = omap3xxx_dss_venc_slaves, .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_venc_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | @@ -2910,6 +2957,10 @@ static struct omap_hwmod_class omap36xx_smartreflex_hwmod_class = { }; /* SR1 */ +static struct omap_smartreflex_dev_attr sr1_dev_attr = { + .sensor_voltdm_name = "mpu_iva", +}; + static struct omap_hwmod_ocp_if *omap3_sr1_slaves[] = { &omap3_l4_core__sr1, }; @@ -2918,7 +2969,6 @@ static struct omap_hwmod omap34xx_sr1_hwmod = { .name = "sr1_hwmod", .class = &omap34xx_smartreflex_hwmod_class, .main_clk = "sr1_fck", - .vdd_name = "mpu", .prcm = { .omap2 = { .prcm_reg_id = 1, @@ -2930,9 +2980,12 @@ static struct omap_hwmod omap34xx_sr1_hwmod = { }, .slaves = omap3_sr1_slaves, .slaves_cnt = ARRAY_SIZE(omap3_sr1_slaves), + .dev_attr = &sr1_dev_attr, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2 | CHIP_IS_OMAP3430ES3_0 | CHIP_IS_OMAP3430ES3_1), + .mpu_irqs = omap3_smartreflex_mpu_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap3_smartreflex_mpu_irqs), .flags = HWMOD_SET_DEFAULT_CLOCKACT, }; @@ -2940,7 +2993,6 @@ static struct omap_hwmod omap36xx_sr1_hwmod = { .name = "sr1_hwmod", .class = &omap36xx_smartreflex_hwmod_class, .main_clk = "sr1_fck", - .vdd_name = "mpu", .prcm = { .omap2 = { .prcm_reg_id = 1, @@ -2952,10 +3004,17 @@ static struct omap_hwmod omap36xx_sr1_hwmod = { }, .slaves = omap3_sr1_slaves, .slaves_cnt = ARRAY_SIZE(omap3_sr1_slaves), + .dev_attr = &sr1_dev_attr, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1), + .mpu_irqs = omap3_smartreflex_mpu_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap3_smartreflex_mpu_irqs), }; /* SR2 */ +static struct omap_smartreflex_dev_attr sr2_dev_attr = { + .sensor_voltdm_name = "core", +}; + static struct omap_hwmod_ocp_if *omap3_sr2_slaves[] = { &omap3_l4_core__sr2, }; @@ -2964,7 +3023,6 @@ static struct omap_hwmod omap34xx_sr2_hwmod = { .name = "sr2_hwmod", .class = &omap34xx_smartreflex_hwmod_class, .main_clk = "sr2_fck", - .vdd_name = "core", .prcm = { .omap2 = { .prcm_reg_id = 1, @@ -2976,9 +3034,12 @@ static struct omap_hwmod omap34xx_sr2_hwmod = { }, .slaves = omap3_sr2_slaves, .slaves_cnt = ARRAY_SIZE(omap3_sr2_slaves), + .dev_attr = &sr2_dev_attr, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2 | CHIP_IS_OMAP3430ES3_0 | CHIP_IS_OMAP3430ES3_1), + .mpu_irqs = omap3_smartreflex_core_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap3_smartreflex_core_irqs), .flags = HWMOD_SET_DEFAULT_CLOCKACT, }; @@ -2986,7 +3047,6 @@ static struct omap_hwmod omap36xx_sr2_hwmod = { .name = "sr2_hwmod", .class = &omap36xx_smartreflex_hwmod_class, .main_clk = "sr2_fck", - .vdd_name = "core", .prcm = { .omap2 = { .prcm_reg_id = 1, @@ -2998,7 +3058,10 @@ static struct omap_hwmod omap36xx_sr2_hwmod = { }, .slaves = omap3_sr2_slaves, .slaves_cnt = ARRAY_SIZE(omap3_sr2_slaves), + .dev_attr = &sr2_dev_attr, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1), + .mpu_irqs = omap3_smartreflex_core_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap3_smartreflex_core_irqs), }; /* @@ -3574,6 +3637,276 @@ static struct omap_hwmod omap3xxx_mmc3_hwmod = { .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), }; +/* + * 'usb_host_hs' class + * high-speed multi-port usb host controller + */ +static struct omap_hwmod_ocp_if omap34xx_usb_host_hs__l3_main_2 = { + .master = &omap34xx_usb_host_hs_hwmod, + .slave = &omap3xxx_l3_main_hwmod, + .clk = "core_l3_ick", + .user = OCP_USER_MPU, +}; + +static struct omap_hwmod_class_sysconfig omap34xx_usb_host_hs_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + .syss_offs = 0x0014, + .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class omap34xx_usb_host_hs_hwmod_class = { + .name = "usbhs_uhh", + .sysc = &omap34xx_usb_host_hs_sysc, +}; + +static struct omap_hwmod_ocp_if *omap34xx_usb_host_hs_masters[] = { + &omap34xx_usb_host_hs__l3_main_2, +}; + +static struct omap_hwmod_addr_space omap34xx_usb_host_hs_addrs[] = { + { + .name = "uhh", + .pa_start = 0x48064000, + .pa_end = 0x480643ff, + .flags = ADDR_TYPE_RT + } +}; + +static struct omap_hwmod_ocp_if omap34xx_l4_cfg__usb_host_hs = { + .master = &omap3xxx_l4_core_hwmod, + .slave = &omap34xx_usb_host_hs_hwmod, + .clk = "l4_ick", + .addr = omap34xx_usb_host_hs_addrs, + .addr_cnt = ARRAY_SIZE(omap34xx_usb_host_hs_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if omap34xx_f128m_cfg__usb_host_hs = { + .clk = "usbhost_120m_fck", + .user = OCP_USER_MPU, + .flags = OCPIF_SWSUP_IDLE, +}; + +static struct omap_hwmod_ocp_if omap34xx_f48m_cfg__usb_host_hs = { + .clk = "usbhost_48m_fck", + .user = OCP_USER_MPU, + .flags = OCPIF_SWSUP_IDLE, +}; + +static struct omap_hwmod_ocp_if *omap34xx_usb_host_hs_slaves[] = { + &omap34xx_l4_cfg__usb_host_hs, + &omap34xx_f128m_cfg__usb_host_hs, + &omap34xx_f48m_cfg__usb_host_hs, +}; + +static struct omap_hwmod omap34xx_usb_host_hs_hwmod = { + .name = "usbhs_uhh", + .class = &omap34xx_usb_host_hs_hwmod_class, + .main_clk = "usbhost_ick", + .prcm = { + .omap2 = { + .module_offs = OMAP3430ES2_USBHOST_MOD, + .prcm_reg_id = 1, + .module_bit = 0, + .idlest_reg_id = 1, + .idlest_idle_bit = 1, + .idlest_stdby_bit = 0, + }, + }, + .slaves = omap34xx_usb_host_hs_slaves, + .slaves_cnt = ARRAY_SIZE(omap34xx_usb_host_hs_slaves), + .masters = omap34xx_usb_host_hs_masters, + .masters_cnt = ARRAY_SIZE(omap34xx_usb_host_hs_masters), + .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), +}; + +/* 'usbhs_ohci' class */ +static struct omap_hwmod_ocp_if omap34xx_usbhs_ohci__l3_main_2 = { + .master = &omap34xx_usbhs_ohci_hwmod, + .slave = &omap3xxx_l3_main_hwmod, + .clk = "core_l3_ick", + .user = OCP_USER_MPU, +}; + +static struct omap_hwmod_class omap34xx_usbhs_ohci_hwmod_class = { + .name = "usbhs_ohci", +}; + +static struct omap_hwmod_ocp_if *omap34xx_usbhs_ohci_masters[] = { + &omap34xx_usbhs_ohci__l3_main_2, +}; + +static struct omap_hwmod_irq_info omap34xx_usbhs_ohci_irqs[] = { + { .name = "ohci-irq", .irq = 76 }, +}; + +static struct omap_hwmod_addr_space omap34xx_usbhs_ohci_addrs[] = { + { + .name = "ohci", + .pa_start = 0x48064400, + .pa_end = 0x480647FF, + .flags = ADDR_MAP_ON_INIT + } +}; + +static struct omap_hwmod_ocp_if omap34xx_l4_cfg__usbhs_ohci = { + .master = &omap3xxx_l4_core_hwmod, + .slave = &omap34xx_usbhs_ohci_hwmod, + .clk = "l4_ick", + .addr = omap34xx_usbhs_ohci_addrs, + .addr_cnt = ARRAY_SIZE(omap34xx_usbhs_ohci_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if *omap34xx_usbhs_ohci_slaves[] = { + &omap34xx_l4_cfg__usbhs_ohci, +}; + +static struct omap_hwmod omap34xx_usbhs_ohci_hwmod = { + .name = "usbhs_ohci", + .class = &omap34xx_usbhs_ohci_hwmod_class, + .mpu_irqs = omap34xx_usbhs_ohci_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_usbhs_ohci_irqs), + .slaves = omap34xx_usbhs_ohci_slaves, + .slaves_cnt = ARRAY_SIZE(omap34xx_usbhs_ohci_slaves), + .masters = omap34xx_usbhs_ohci_masters, + .masters_cnt = ARRAY_SIZE(omap34xx_usbhs_ohci_masters), + .flags = HWMOD_INIT_NO_RESET | HWMOD_NO_IDLEST, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), +}; + +/* 'usbhs_ehci' class */ +static struct omap_hwmod_ocp_if omap34xx_usbhs_ehci__l3_main_2 = { + .master = &omap34xx_usbhs_ehci_hwmod, + .slave = &omap3xxx_l3_main_hwmod, + .clk = "core_l3_ick", + .user = OCP_USER_MPU, +}; + +static struct omap_hwmod_class omap34xx_usbhs_ehci_hwmod_class = { + .name = "usbhs_ehci", +}; + +static struct omap_hwmod_ocp_if *omap34xx_usbhs_ehci_masters[] = { + &omap34xx_usbhs_ehci__l3_main_2, +}; + +static struct omap_hwmod_irq_info omap34xx_usbhs_ehci_irqs[] = { + { .name = "ehci-irq", .irq = 77 }, +}; + +static struct omap_hwmod_addr_space omap34xx_usbhs_ehci_addrs[] = { + { + .name = "ehci", + .pa_start = 0x48064800, + .pa_end = 0x48064CFF, + .flags = ADDR_MAP_ON_INIT + } +}; + +static struct omap_hwmod_ocp_if omap34xx_l4_cfg__usbhs_ehci = { + .master = &omap3xxx_l4_core_hwmod, + .slave = &omap34xx_usbhs_ehci_hwmod, + .clk = "l4_ick", + .addr = omap34xx_usbhs_ehci_addrs, + .addr_cnt = ARRAY_SIZE(omap34xx_usbhs_ehci_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if *omap34xx_usbhs_ehci_slaves[] = { + &omap34xx_l4_cfg__usbhs_ehci, +}; + +static struct omap_hwmod omap34xx_usbhs_ehci_hwmod = { + .name = "usbhs_ehci", + .class = &omap34xx_usbhs_ehci_hwmod_class, + .mpu_irqs = omap34xx_usbhs_ehci_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_usbhs_ehci_irqs), + .slaves = omap34xx_usbhs_ehci_slaves, + .slaves_cnt = ARRAY_SIZE(omap34xx_usbhs_ehci_slaves), + .masters = omap34xx_usbhs_ehci_masters, + .masters_cnt = ARRAY_SIZE(omap34xx_usbhs_ehci_masters), + .flags = HWMOD_INIT_NO_RESET | HWMOD_NO_IDLEST, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), +}; + +/* + * 'usb_tll_hs' class + * usb_tll_hs module is the adapter on the usb_host_hs ports + */ +static struct omap_hwmod_class_sysconfig omap34xx_usb_tll_hs_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + .syss_offs = 0x0014, + .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class omap34xx_usb_tll_hs_hwmod_class = { + .name = "usbhs_tll", + .sysc = &omap34xx_usb_tll_hs_sysc, +}; + +static struct omap_hwmod_irq_info omap34xx_usb_tll_hs_irqs[] = { + { .name = "tll-irq", .irq = 78 }, +}; + +static struct omap_hwmod_addr_space omap34xx_usb_tll_hs_addrs[] = { + { + .name = "tll", + .pa_start = 0x48062000, + .pa_end = 0x48062fff, + .flags = ADDR_TYPE_RT + }, +}; + +static struct omap_hwmod_ocp_if omap34xx_f_cfg__usb_tll_hs = { + .clk = "usbtll_fck", + .user = OCP_USER_MPU, + .flags = OCPIF_SWSUP_IDLE, +}; + +static struct omap_hwmod_ocp_if omap34xx_l4_cfg__usb_tll_hs = { + .master = &omap3xxx_l4_core_hwmod, + .slave = &omap34xx_usb_tll_hs_hwmod, + .clk = "l4_ick", + .addr = omap34xx_usb_tll_hs_addrs, + .addr_cnt = ARRAY_SIZE(omap34xx_usb_tll_hs_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if *omap34xx_usb_tll_hs_slaves[] = { + &omap34xx_l4_cfg__usb_tll_hs, + &omap34xx_f_cfg__usb_tll_hs, +}; + +static struct omap_hwmod omap34xx_usb_tll_hs_hwmod = { + .name = "usbhs_tll", + .class = &omap34xx_usb_tll_hs_hwmod_class, + .mpu_irqs = omap34xx_usb_tll_hs_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_usb_tll_hs_irqs), + .main_clk = "usbtll_ick", + .prcm = { + .omap2 = { + .module_offs = CORE_MOD, + .prcm_reg_id = 3, + .module_bit = 2, + .idlest_reg_id = 3, + .idlest_idle_bit = 2, + }, + }, + .slaves = omap34xx_usb_tll_hs_slaves, + .slaves_cnt = ARRAY_SIZE(omap34xx_usb_tll_hs_slaves), + .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), +}; + static __initdata struct omap_hwmod *omap3xxx_hwmods[] = { &omap3xxx_l3_main_hwmod, &omap3xxx_l4_core_hwmod, @@ -3656,6 +3989,11 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = { /* usbotg for am35x */ &am35xx_usbhsotg_hwmod, + &omap34xx_usb_host_hs_hwmod, + &omap34xx_usbhs_ohci_hwmod, + &omap34xx_usbhs_ehci_hwmod, + &omap34xx_usb_tll_hs_hwmod, + NULL, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index e1c69ff..b5c5b10 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -27,9 +27,11 @@ #include <plat/mcspi.h> #include <plat/mcbsp.h> #include <plat/mmc.h> +#include <plat/dmtimer.h> #include "omap_hwmod_common_data.h" +#include "smartreflex.h" #include "cm1_44xx.h" #include "cm2_44xx.h" #include "prm44xx.h" @@ -49,6 +51,8 @@ static struct omap_hwmod omap44xx_dmm_hwmod; static struct omap_hwmod omap44xx_dsp_hwmod; static struct omap_hwmod omap44xx_dss_hwmod; static struct omap_hwmod omap44xx_emif_fw_hwmod; +static struct omap_hwmod omap44xx_fdif_hwmod; +static struct omap_hwmod omap44xx_gpu_hwmod; static struct omap_hwmod omap44xx_hsi_hwmod; static struct omap_hwmod omap44xx_ipu_hwmod; static struct omap_hwmod omap44xx_iss_hwmod; @@ -65,7 +69,12 @@ static struct omap_hwmod omap44xx_mmc1_hwmod; static struct omap_hwmod omap44xx_mmc2_hwmod; static struct omap_hwmod omap44xx_mpu_hwmod; static struct omap_hwmod omap44xx_mpu_private_hwmod; +static struct omap_hwmod omap44xx_sl2if_hwmod; static struct omap_hwmod omap44xx_usb_otg_hs_hwmod; +static struct omap_hwmod omap44xx_usb_host_hs_hwmod; +static struct omap_hwmod omap44xx_usbhs_ohci_hwmod; +static struct omap_hwmod omap44xx_usbhs_ehci_hwmod; +static struct omap_hwmod omap44xx_usb_tll_hs_hwmod; /* * Interconnects omap_hwmod structures @@ -124,7 +133,7 @@ static struct omap_hwmod omap44xx_dmm_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_dmm_slaves), .mpu_irqs = omap44xx_dmm_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dmm_irqs), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -173,7 +182,7 @@ static struct omap_hwmod omap44xx_emif_fw_hwmod = { .class = &omap44xx_emif_fw_hwmod_class, .slaves = omap44xx_emif_fw_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_emif_fw_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -212,7 +221,7 @@ static struct omap_hwmod omap44xx_l3_instr_hwmod = { .class = &omap44xx_l3_hwmod_class, .slaves = omap44xx_l3_instr_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_l3_instr_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* l3_main_1 interface data */ @@ -306,7 +315,7 @@ static struct omap_hwmod omap44xx_l3_main_1_hwmod = { .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_l3_targ_irqs), .slaves = omap44xx_l3_main_1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_1_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* l3_main_2 interface data */ @@ -318,6 +327,14 @@ static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* gpu -> l3_main_2 */ +static struct omap_hwmod_ocp_if omap44xx_gpu__l3_main_2 = { + .master = &omap44xx_gpu_hwmod, + .slave = &omap44xx_l3_main_2_hwmod, + .clk = "l3_div_ck", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + /* hsi -> l3_main_2 */ static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = { .master = &omap44xx_hsi_hwmod, @@ -342,6 +359,14 @@ static struct omap_hwmod_ocp_if omap44xx_iss__l3_main_2 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* fdif -> l3_main_2 */ +static struct omap_hwmod_ocp_if omap44xx_fdif__l3_main_2 = { + .master = &omap44xx_fdif_hwmod, + .slave = &omap44xx_l3_main_2_hwmod, + .clk = "l3_div_ck", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + /* iva -> l3_main_2 */ static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = { .master = &omap44xx_iva_hwmod, @@ -390,8 +415,10 @@ static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = { &omap44xx_hsi__l3_main_2, &omap44xx_ipu__l3_main_2, &omap44xx_iss__l3_main_2, + &omap44xx_fdif__l3_main_2, &omap44xx_iva__l3_main_2, &omap44xx_l3_main_1__l3_main_2, + &omap44xx_gpu__l3_main_2, &omap44xx_l4_cfg__l3_main_2, &omap44xx_usb_otg_hs__l3_main_2, }; @@ -401,7 +428,7 @@ static struct omap_hwmod omap44xx_l3_main_2_hwmod = { .class = &omap44xx_l3_hwmod_class, .slaves = omap44xx_l3_main_2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* l3_main_3 interface data */ @@ -451,7 +478,7 @@ static struct omap_hwmod omap44xx_l3_main_3_hwmod = { .class = &omap44xx_l3_hwmod_class, .slaves = omap44xx_l3_main_3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -508,7 +535,7 @@ static struct omap_hwmod omap44xx_l4_abe_hwmod = { .class = &omap44xx_l4_hwmod_class, .slaves = omap44xx_l4_abe_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_l4_abe_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* l4_cfg interface data */ @@ -530,7 +557,7 @@ static struct omap_hwmod omap44xx_l4_cfg_hwmod = { .class = &omap44xx_l4_hwmod_class, .slaves = omap44xx_l4_cfg_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_l4_cfg_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* l4_per interface data */ @@ -552,7 +579,7 @@ static struct omap_hwmod omap44xx_l4_per_hwmod = { .class = &omap44xx_l4_hwmod_class, .slaves = omap44xx_l4_per_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_l4_per_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* l4_wkup interface data */ @@ -574,7 +601,7 @@ static struct omap_hwmod omap44xx_l4_wkup_hwmod = { .class = &omap44xx_l4_hwmod_class, .slaves = omap44xx_l4_wkup_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_l4_wkup_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -604,7 +631,7 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = { .class = &omap44xx_mpu_bus_hwmod_class, .slaves = omap44xx_mpu_private_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mpu_private_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -629,7 +656,6 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = { * elm * emif1 * emif2 - * fdif * gpmc * gpu * hdq1w @@ -640,7 +666,6 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = { * prcm_mpu * prm * scrm - * sl2if * slimbus1 * slimbus2 * usb_host_fs @@ -651,6 +676,222 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = { */ /* + * 'mpu' class + * mpu sub-system + */ + +static struct omap_hwmod_class omap44xx_mpu_hwmod_class = { + .name = "mpu", +}; + +/* mpu */ +static struct omap_hwmod_irq_info omap44xx_mpu_irqs[] = { + { .name = "pl310", .irq = 0 + OMAP44XX_IRQ_GIC_START }, + { .name = "cti0", .irq = 1 + OMAP44XX_IRQ_GIC_START }, + { .name = "cti1", .irq = 2 + OMAP44XX_IRQ_GIC_START }, +}; + +/* mpu master ports */ +static struct omap_hwmod_ocp_if *omap44xx_mpu_masters[] = { + &omap44xx_mpu__l3_main_1, + &omap44xx_mpu__l4_abe, + &omap44xx_mpu__dmm, +}; + +static struct omap_hwmod omap44xx_mpu_hwmod = { + .name = "mpu", + .class = &omap44xx_mpu_hwmod_class, + .flags = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET), + .mpu_irqs = omap44xx_mpu_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mpu_irqs), + .main_clk = "dpll_mpu_m2_ck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_MPU_MPU_CLKCTRL, + }, + }, + .masters = omap44xx_mpu_masters, + .masters_cnt = ARRAY_SIZE(omap44xx_mpu_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* + * 'smartreflex' class + * smartreflex module (monitor silicon performance and outputs a measure of + * performance error) + */ + +/* The IP is not compliant to type1 / type2 scheme */ +static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_smartreflex = { + .sidle_shift = 24, + .enwkup_shift = 26, +}; + +static struct omap_hwmod_class_sysconfig omap44xx_smartreflex_sysc = { + .sysc_offs = 0x0038, + .sysc_flags = (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + SIDLE_SMART_WKUP), + .sysc_fields = &omap_hwmod_sysc_type_smartreflex, +}; + +static struct omap_hwmod_class omap44xx_smartreflex_hwmod_class = { + .name = "smartreflex", + .sysc = &omap44xx_smartreflex_sysc, + .rev = 2, +}; + +/* smartreflex_core */ +static struct omap_smartreflex_dev_attr smartreflex_core_dev_attr = { + .sensor_voltdm_name = "core", +}; + +static struct omap_hwmod omap44xx_smartreflex_core_hwmod; +static struct omap_hwmod_irq_info omap44xx_smartreflex_core_irqs[] = { + { .irq = 19 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_smartreflex_core_addrs[] = { + { + .pa_start = 0x4a0dd000, + .pa_end = 0x4a0dd03f, + .flags = ADDR_TYPE_RT + }, +}; + +/* l4_cfg -> smartreflex_core */ +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_core = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_smartreflex_core_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_smartreflex_core_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_smartreflex_core_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* smartreflex_core slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_smartreflex_core_slaves[] = { + &omap44xx_l4_cfg__smartreflex_core, +}; + +static struct omap_hwmod omap44xx_smartreflex_core_hwmod = { + .name = "smartreflex_core", + .class = &omap44xx_smartreflex_hwmod_class, + .mpu_irqs = omap44xx_smartreflex_core_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_smartreflex_core_irqs), + .main_clk = "smartreflex_core_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_ALWON_SR_CORE_CLKCTRL, + }, + }, + .slaves = omap44xx_smartreflex_core_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_core_slaves), + .dev_attr = &smartreflex_core_dev_attr, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* smartreflex_iva */ +static struct omap_smartreflex_dev_attr smartreflex_iva_dev_attr = { + .sensor_voltdm_name = "iva", +}; + +static struct omap_hwmod omap44xx_smartreflex_iva_hwmod; +static struct omap_hwmod_irq_info omap44xx_smartreflex_iva_irqs[] = { + { .irq = 102 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_smartreflex_iva_addrs[] = { + { + .pa_start = 0x4a0db000, + .pa_end = 0x4a0db03f, + .flags = ADDR_TYPE_RT + }, +}; + +/* l4_cfg -> smartreflex_iva */ +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_iva = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_smartreflex_iva_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_smartreflex_iva_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_smartreflex_iva_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* smartreflex_iva slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_smartreflex_iva_slaves[] = { + &omap44xx_l4_cfg__smartreflex_iva, +}; + +static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = { + .name = "smartreflex_iva", + .class = &omap44xx_smartreflex_hwmod_class, + .mpu_irqs = omap44xx_smartreflex_iva_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_smartreflex_iva_irqs), + .main_clk = "smartreflex_iva_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_ALWON_SR_IVA_CLKCTRL, + }, + }, + .slaves = omap44xx_smartreflex_iva_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_iva_slaves), + .dev_attr = &smartreflex_iva_dev_attr, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* smartreflex_mpu */ +static struct omap_smartreflex_dev_attr smartreflex_mpu_dev_attr = { + .sensor_voltdm_name = "mpu", +}; + +static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod; +static struct omap_hwmod_irq_info omap44xx_smartreflex_mpu_irqs[] = { + { .irq = 18 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_smartreflex_mpu_addrs[] = { + { + .pa_start = 0x4a0d9000, + .pa_end = 0x4a0d903f, + .flags = ADDR_TYPE_RT + }, +}; + +/* l4_cfg -> smartreflex_mpu */ +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_mpu = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_smartreflex_mpu_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_smartreflex_mpu_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_smartreflex_mpu_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* smartreflex_mpu slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_smartreflex_mpu_slaves[] = { + &omap44xx_l4_cfg__smartreflex_mpu, +}; + +static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = { + .name = "smartreflex_mpu", + .class = &omap44xx_smartreflex_hwmod_class, + .mpu_irqs = omap44xx_smartreflex_mpu_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_smartreflex_mpu_irqs), + .main_clk = "smartreflex_mpu_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_ALWON_SR_MPU_CLKCTRL, + }, + }, + .slaves = omap44xx_smartreflex_mpu_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_mpu_slaves), + .dev_attr = &smartreflex_mpu_dev_attr, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* * 'aess' class * audio engine sub system */ @@ -658,7 +899,7 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = { static struct omap_hwmod_class_sysconfig omap44xx_aess_sysc = { .rev_offs = 0x0000, .sysc_offs = 0x0010, - .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE), + .sysc_flags = 0, .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART), .sysc_fields = &omap_hwmod_sysc_type2, @@ -692,6 +933,27 @@ static struct omap_hwmod_ocp_if *omap44xx_aess_masters[] = { static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = { { + .name = "dmem", + .pa_start = 0x40180000, + .pa_end = 0x4018ffff + }, + { + .name = "cmem", + .pa_start = 0x401a0000, + .pa_end = 0x401a1fff + }, + { + .name = "smem", + .pa_start = 0x401c0000, + .pa_end = 0x401c5fff + }, + { + .name = "pmem", + .pa_start = 0x401e0000, + .pa_end = 0x401e1fff + }, + { + .name = "mpu", .pa_start = 0x401f1000, .pa_end = 0x401f13ff, .flags = ADDR_TYPE_RT @@ -710,6 +972,27 @@ static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess = { static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = { { + .name = "dmem_dma", + .pa_start = 0x49080000, + .pa_end = 0x4908ffff + }, + { + .name = "cmem_dma", + .pa_start = 0x490a0000, + .pa_end = 0x490a1fff + }, + { + .name = "smem_dma", + .pa_start = 0x490c0000, + .pa_end = 0x490c5fff + }, + { + .name = "pmem_dma", + .pa_start = 0x490e0000, + .pa_end = 0x490e1fff + }, + { + .name = "dma", .pa_start = 0x490f1000, .pa_end = 0x490f13ff, .flags = ADDR_TYPE_RT @@ -743,13 +1026,132 @@ static struct omap_hwmod omap44xx_aess_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM1_ABE_AESS_CLKCTRL, + .context_reg = OMAP4430_RM_ABE_AESS_CONTEXT, }, }, .slaves = omap44xx_aess_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_aess_slaves), .masters = omap44xx_aess_masters, .masters_cnt = ARRAY_SIZE(omap44xx_aess_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* + * 'ctrl_module' class + * attila core control module + */ + +static struct omap_hwmod_class_sysconfig omap44xx_ctrl_module_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + .sysc_flags = SYSC_HAS_SIDLEMODE, + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + SIDLE_SMART_WKUP), + .sysc_fields = &omap_hwmod_sysc_type2, +}; + +static struct omap_hwmod_class omap44xx_ctrl_module_hwmod_class = { + .name = "ctrl_module", + .sysc = &omap44xx_ctrl_module_sysc, +}; + +/* ctrl_module_core */ +static struct omap_hwmod omap44xx_ctrl_module_core_hwmod; +static struct omap_hwmod_irq_info omap44xx_ctrl_module_core_irqs[] = { + { .name = "sec_evts", .irq = 8 + OMAP44XX_IRQ_GIC_START }, + { .name = "thermal_alert", .irq = 126 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_ctrl_module_core_addrs[] = { + { + .pa_start = 0x4a002000, + .pa_end = 0x4a0027ff, + + .flags = ADDR_TYPE_RT + }, +}; + +/* l4_cfg -> ctrl_module_core */ +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ctrl_module_core = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_ctrl_module_core_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_ctrl_module_core_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_ctrl_module_core_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* ctrl_module_core slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_ctrl_module_core_slaves[] = { + &omap44xx_l4_cfg__ctrl_module_core, +}; + +static struct omap_hwmod omap44xx_ctrl_module_core_hwmod = { + .name = "ctrl_module_core", + .class = &omap44xx_ctrl_module_hwmod_class, + .mpu_irqs = omap44xx_ctrl_module_core_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_ctrl_module_core_irqs), + .main_clk = "l4_div_ck", + .slaves = omap44xx_ctrl_module_core_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_ctrl_module_core_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP446X), +}; +/* + * 'thermal_sensor' class + * thermal sensor module inside the bandgap / control module + */ + +static struct omap_hwmod_class omap44xx_thermal_sensor_hwmod_class = { + .name = "thermal_sensor", +}; + +static struct omap_hwmod_irq_info omap44xx_thermal_sensor_irqs[] = { + { .name = "thermal_alert", .irq = 126 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_thermal_sensor_addrs[] = { + { + .pa_start = 0x4a002378, + .pa_end = 0x4a0023ff, + }, +}; + +static struct omap_hwmod omap44xx_thermal_sensor_hwmod; +/* l4_cfg -> ctrl_module_core */ +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__thermal_sensor = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_thermal_sensor_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_thermal_sensor_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_thermal_sensor_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* ctrl_module_core slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_thermal_sensor_slaves[] = { + &omap44xx_l4_cfg__thermal_sensor, +}; + +static struct omap_hwmod_opt_clk thermal_sensor446x_opt_clks[] = { + { .role = "fclk", .clk = "bandgap_ts_fclk" }, +}; + +static struct omap_hwmod omap44xx_thermal_sensor_hwmod = { + .name = "thermal_sensor", + .class = &omap44xx_thermal_sensor_hwmod_class, + .mpu_irqs = omap44xx_thermal_sensor_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_thermal_sensor_irqs), + .main_clk = "bandgap_ts_fclk", + .slaves = omap44xx_thermal_sensor_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_thermal_sensor_slaves), + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, + }, + }, + .opt_clks = thermal_sensor446x_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(thermal_sensor446x_opt_clks), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP446X), }; /* @@ -762,11 +1164,28 @@ static struct omap_hwmod_class omap44xx_bandgap_hwmod_class = { }; /* bandgap */ -static struct omap_hwmod_opt_clk bandgap_opt_clks[] = { +static struct omap_hwmod_opt_clk bandgap443x_opt_clks[] = { { .role = "fclk", .clk = "bandgap_fclk" }, }; -static struct omap_hwmod omap44xx_bandgap_hwmod = { +static struct omap_hwmod omap443x_bandgap_hwmod = { + .name = "bandgap", + .class = &omap44xx_bandgap_hwmod_class, + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, + }, + }, + .opt_clks = bandgap443x_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(bandgap443x_opt_clks), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP443X), +}; + +static struct omap_hwmod_opt_clk bandgap446x_opt_clks[] = { + { .role = "fclk", .clk = "bandgap_ts_fclk" }, +}; + +static struct omap_hwmod omap446x_bandgap_hwmod = { .name = "bandgap", .class = &omap44xx_bandgap_hwmod_class, .prcm = { @@ -774,9 +1193,9 @@ static struct omap_hwmod omap44xx_bandgap_hwmod = { .clkctrl_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, }, }, - .opt_clks = bandgap_opt_clks, - .opt_clks_cnt = ARRAY_SIZE(bandgap_opt_clks), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .opt_clks = bandgap446x_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(bandgap446x_opt_clks), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP446X), }; /* @@ -835,7 +1254,7 @@ static struct omap_hwmod omap44xx_counter_32k_hwmod = { }, .slaves = omap44xx_counter_32k_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_counter_32k_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -921,7 +1340,7 @@ static struct omap_hwmod omap44xx_dma_system_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_dma_system_slaves), .masters = omap44xx_dma_system_masters, .masters_cnt = ARRAY_SIZE(omap44xx_dma_system_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1011,7 +1430,7 @@ static struct omap_hwmod omap44xx_dmic_hwmod = { }, .slaves = omap44xx_dmic_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dmic_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1036,6 +1455,14 @@ static struct omap_hwmod_rst_info omap44xx_dsp_c0_resets[] = { { .name = "dsp", .rst_shift = 0 }, }; +static struct omap_hwmod_addr_space omap44xx_dsp_addrs[] = { + { + .pa_start = 0x4A066000, + .pa_end = 0x4A0660ff, + .flags = ADDR_TYPE_RT + }, +}; + /* dsp -> iva */ static struct omap_hwmod_ocp_if omap44xx_dsp__iva = { .master = &omap44xx_dsp_hwmod, @@ -1043,11 +1470,19 @@ static struct omap_hwmod_ocp_if omap44xx_dsp__iva = { .clk = "dpll_iva_m5x2_ck", }; +/* dsp -> sl2if */ +static struct omap_hwmod_ocp_if omap44xx_dsp__sl2if = { + .master = &omap44xx_dsp_hwmod, + .slave = &omap44xx_sl2if_hwmod, + .clk = "dpll_iva_m5x2_ck", +}; + /* dsp master ports */ static struct omap_hwmod_ocp_if *omap44xx_dsp_masters[] = { &omap44xx_dsp__l3_main_1, &omap44xx_dsp__l4_abe, &omap44xx_dsp__iva, + &omap44xx_dsp__sl2if, }; /* l4_cfg -> dsp */ @@ -1055,6 +1490,8 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__dsp = { .master = &omap44xx_l4_cfg_hwmod, .slave = &omap44xx_dsp_hwmod, .clk = "l4_div_ck", + .addr = omap44xx_dsp_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_dsp_addrs), .user = OCP_USER_MPU | OCP_USER_SDMA, }; @@ -1075,12 +1512,13 @@ static struct omap_hwmod omap44xx_dsp_c0_hwmod = { .rstctrl_reg = OMAP4430_RM_TESLA_RSTCTRL, }, }, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct omap_hwmod omap44xx_dsp_hwmod = { .name = "dsp", .class = &omap44xx_dsp_hwmod_class, + .flags = HWMOD_INIT_NO_RESET, .mpu_irqs = omap44xx_dsp_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dsp_irqs), .rst_lines = omap44xx_dsp_resets, @@ -1096,7 +1534,7 @@ static struct omap_hwmod omap44xx_dsp_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_dsp_slaves), .masters = omap44xx_dsp_masters, .masters_cnt = ARRAY_SIZE(omap44xx_dsp_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1110,9 +1548,67 @@ static struct omap_hwmod_class_sysconfig omap44xx_dss_sysc = { .sysc_flags = SYSS_HAS_RESET_STATUS, }; +static int omap44xx_dss_reset(struct omap_hwmod *oh) +{ +#define DISPC_IRQSTATUS (0x48041018UL) +#define DISPC_CONTROL1 (0x48041040UL) +#define DISPC_CONTROL2 (0x48041238UL) + u32 ctrl1_mask = 0; + u32 ctrl2_mask = 0; + u32 irq_mask = 0; + u32 val; + unsigned long end_wait; + + /* HACK */ + /* If LCD1/LCD2/TV are active, disable them first before + * moving the clock sources back to PRCM. We don't want to change + * the clock source while a DMA is active. + */ + val = omap_readl(DISPC_CONTROL1); + if (val & (1 << 0)) { + /* LCD1 */ + irq_mask |= 1 << 0; + ctrl1_mask |= 1 << 0; + } + if (val & (1 << 1)) { + /* TV/VENC */ + irq_mask |= 1 << 24; + ctrl1_mask |= 1 << 1; + } + val = omap_readl(DISPC_CONTROL2); + if (val & (1 << 0)) { + /* LCD2 */ + irq_mask |= 1 << 22; + ctrl2_mask |= 1 << 0; + } + + /* disable the active controllers */ + omap_writel(omap_readl(DISPC_CONTROL1) & (~ctrl1_mask), DISPC_CONTROL1); + omap_writel(omap_readl(DISPC_CONTROL2) & (~ctrl2_mask), DISPC_CONTROL2); + + omap_writel(irq_mask, DISPC_IRQSTATUS); + + end_wait = jiffies + msecs_to_jiffies(50); + while (((omap_readl(DISPC_CONTROL1) & ctrl1_mask) || + (omap_readl(DISPC_CONTROL2) & ctrl2_mask) || + ((omap_readl(DISPC_IRQSTATUS) & irq_mask) != irq_mask)) && + time_before(jiffies, end_wait)) + cpu_relax(); + WARN_ON((omap_readl(DISPC_CONTROL1) & ctrl1_mask) || + (omap_readl(DISPC_CONTROL2) & ctrl2_mask) || + ((omap_readl(DISPC_IRQSTATUS) & irq_mask) != irq_mask)); + + omap_hwmod_write(0x0, oh, 0x40); + return 0; +#undef DISPC_IRQSTATUS +#undef DISPC_CONTROL1 +#undef DISPC_CONTROL2 +} + static struct omap_hwmod_class omap44xx_dss_hwmod_class = { .name = "dss", .sysc = &omap44xx_dss_sysc, + .reset = omap44xx_dss_reset, }; /* dss */ @@ -1164,15 +1660,15 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_slaves[] = { }; static struct omap_hwmod_opt_clk dss_opt_clks[] = { - { .role = "sys_clk", .clk = "dss_sys_clk" }, - { .role = "tv_clk", .clk = "dss_tv_clk" }, { .role = "dss_clk", .clk = "dss_dss_clk" }, - { .role = "video_clk", .clk = "dss_48mhz_clk" }, }; static struct omap_hwmod omap44xx_dss_hwmod = { .name = "dss_core", .class = &omap44xx_dss_hwmod_class, +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = HWMOD_INIT_NO_RESET, +#endif .main_clk = "dss_fck", .prcm = { .omap4 = { @@ -1185,7 +1681,7 @@ static struct omap_hwmod omap44xx_dss_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_dss_slaves), .masters = omap44xx_dss_masters, .masters_cnt = ARRAY_SIZE(omap44xx_dss_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1263,9 +1759,25 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_dispc_slaves[] = { &omap44xx_l4_per__dss_dispc, }; +static struct omap_hwmod_opt_clk dispc_opt_clks[] = { + { .role = "dss_clk", .clk = "dss_dss_clk" }, + /* + * The rest of the clocks are not needed by the driver, + * but are needed by the hwmod to reset DSS properly. + */ + { .role = "sys_clk", .clk = "dss_sys_clk" }, + { .role = "tv_clk", .clk = "dss_tv_clk" }, + { .role = "hdmi_clk", .clk = "dss_48mhz_clk" }, +}; + static struct omap_hwmod omap44xx_dss_dispc_hwmod = { .name = "dss_dispc", .class = &omap44xx_dispc_hwmod_class, +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET | HWMOD_INIT_NO_RESET, +#else + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, +#endif .mpu_irqs = omap44xx_dss_dispc_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_dispc_irqs), .sdma_reqs = omap44xx_dss_dispc_sdma_reqs, @@ -1274,11 +1786,14 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, + .context_reg = OMAP4430_RM_DSS_DSS_CONTEXT, }, }, + .opt_clks = dispc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dispc_opt_clks), .slaves = omap44xx_dss_dispc_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dispc_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1354,9 +1869,17 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_dsi1_slaves[] = { &omap44xx_l4_per__dss_dsi1, }; +static struct omap_hwmod_opt_clk dsi1_opt_clks[] = { + { .role = "dss_clk", .clk = "dss_dss_clk" }, + { .role = "sys_clk", .clk = "dss_sys_clk" }, +}; + static struct omap_hwmod omap44xx_dss_dsi1_hwmod = { .name = "dss_dsi1", .class = &omap44xx_dsi_hwmod_class, +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = HWMOD_INIT_NO_RESET, +#endif .mpu_irqs = omap44xx_dss_dsi1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_irqs), .sdma_reqs = omap44xx_dss_dsi1_sdma_reqs, @@ -1367,9 +1890,11 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = dsi1_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(dsi1_opt_clks), .slaves = omap44xx_dss_dsi1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* dss_dsi2 */ @@ -1427,6 +1952,9 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_dsi2_slaves[] = { static struct omap_hwmod omap44xx_dss_dsi2_hwmod = { .name = "dss_dsi2", .class = &omap44xx_dsi_hwmod_class, +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = HWMOD_INIT_NO_RESET, +#endif .mpu_irqs = omap44xx_dss_dsi2_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_dsi2_irqs), .sdma_reqs = omap44xx_dss_dsi2_sdma_reqs, @@ -1439,7 +1967,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = { }, .slaves = omap44xx_dss_dsi2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dsi2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1514,9 +2042,17 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_hdmi_slaves[] = { &omap44xx_l4_per__dss_hdmi, }; +static struct omap_hwmod_opt_clk hdmi_opt_clks[] = { + { .role = "sys_clk", .clk = "dss_sys_clk" }, + { .role = "hdmi_clk", .clk = "dss_48mhz_clk" }, +}; + static struct omap_hwmod omap44xx_dss_hdmi_hwmod = { .name = "dss_hdmi", .class = &omap44xx_hdmi_hwmod_class, +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = HWMOD_INIT_NO_RESET, +#endif .mpu_irqs = omap44xx_dss_hdmi_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_irqs), .sdma_reqs = omap44xx_dss_hdmi_sdma_reqs, @@ -1527,9 +2063,11 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = hdmi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(hdmi_opt_clks), .slaves = omap44xx_dss_hdmi_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1600,9 +2138,16 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_rfbi_slaves[] = { &omap44xx_l4_per__dss_rfbi, }; +static struct omap_hwmod_opt_clk rfbi_opt_clks[] = { + { .role = "rfbi_iclk", .clk = "dss_fck" }, +}; + static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { .name = "dss_rfbi", .class = &omap44xx_rfbi_hwmod_class, +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = HWMOD_INIT_NO_RESET, +#endif .sdma_reqs = omap44xx_dss_rfbi_sdma_reqs, .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_dss_rfbi_sdma_reqs), .main_clk = "dss_fck", @@ -1611,9 +2156,11 @@ static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = rfbi_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(rfbi_opt_clks), .slaves = omap44xx_dss_rfbi_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_rfbi_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1669,18 +2216,209 @@ static struct omap_hwmod_ocp_if *omap44xx_dss_venc_slaves[] = { &omap44xx_l4_per__dss_venc, }; +static struct omap_hwmod_opt_clk venc_opt_clks[] = { + { .role = "tv_clk", .clk = "dss_tv_clk" }, +}; + static struct omap_hwmod omap44xx_dss_venc_hwmod = { .name = "dss_venc", .class = &omap44xx_venc_hwmod_class, +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + .flags = HWMOD_INIT_NO_RESET, +#endif .main_clk = "dss_fck", .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL, }, }, + .opt_clks = venc_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(venc_opt_clks), .slaves = omap44xx_dss_venc_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_dss_venc_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* + * 'emif' class + * external memory interface no1 + */ + +static struct omap_hwmod_class omap44xx_emif_hwmod_class = { + .name = "emif", +}; + +/* emif1 */ +static struct omap_hwmod omap44xx_emif1_hwmod; +static struct omap_hwmod_irq_info omap44xx_emif1_irqs[] = { + { .irq = 110 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_emif1_addrs[] = { + { + .pa_start = 0x4c000000, + .pa_end = 0x4c0000ff, + .flags = ADDR_TYPE_RT + }, +}; + +/* emif_fw -> emif1 */ +static struct omap_hwmod_ocp_if omap44xx_emif_fw__emif1 = { + .master = &omap44xx_emif_fw_hwmod, + .slave = &omap44xx_emif1_hwmod, + .clk = "l3_div_ck", + .addr = omap44xx_emif1_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_emif1_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* emif1 slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_emif1_slaves[] = { + &omap44xx_emif_fw__emif1, +}; + +static struct omap_hwmod omap44xx_emif1_hwmod = { + .name = "emif1", + .class = &omap44xx_emif_hwmod_class, + .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET, + .mpu_irqs = omap44xx_emif1_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_emif1_irqs), + .main_clk = "emif1_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL, + }, + }, + .slaves = omap44xx_emif1_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_emif1_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* emif2 */ +static struct omap_hwmod omap44xx_emif2_hwmod; +static struct omap_hwmod_irq_info omap44xx_emif2_irqs[] = { + { .irq = 111 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_emif2_addrs[] = { + { + .pa_start = 0x4d000000, + .pa_end = 0x4d0000ff, + .flags = ADDR_TYPE_RT + }, +}; + +/* emif_fw -> emif2 */ +static struct omap_hwmod_ocp_if omap44xx_emif_fw__emif2 = { + .master = &omap44xx_emif_fw_hwmod, + .slave = &omap44xx_emif2_hwmod, + .clk = "l3_div_ck", + .addr = omap44xx_emif2_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_emif2_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* emif2 slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_emif2_slaves[] = { + &omap44xx_emif_fw__emif2, +}; + +static struct omap_hwmod omap44xx_emif2_hwmod = { + .name = "emif2", + .class = &omap44xx_emif_hwmod_class, + .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET, + .mpu_irqs = omap44xx_emif2_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_emif2_irqs), + .main_clk = "emif2_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL, + }, + }, + .slaves = omap44xx_emif2_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_emif2_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + + +/* + * 'fdif' class + * face detection hw accelerator module + */ + +static struct omap_hwmod_class_sysconfig omap44xx_fdif_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + /* + * FDIF needs 100 OCP clk cycles delay after a softreset before + * accessing sysconfig again. + * The lowest frequency at the moment for L3 bus is 100 MHz, so + * 1usec delay is needed. Add an x2 margin to be safe (2 usecs). + * + * TODO: Indicate errata when available. + */ + .srst_udelay = 2, + .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS | + SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART), + .sysc_fields = &omap_hwmod_sysc_type2, +}; + +static struct omap_hwmod_class omap44xx_fdif_hwmod_class = { + .name = "fdif", + .sysc = &omap44xx_fdif_sysc, +}; + +/* fdif */ +static struct omap_hwmod_irq_info omap44xx_fdif_irqs[] = { + { .irq = 69 + OMAP44XX_IRQ_GIC_START }, +}; + +/* fdif master ports */ +static struct omap_hwmod_ocp_if *omap44xx_fdif_masters[] = { + &omap44xx_fdif__l3_main_2, +}; + +static struct omap_hwmod_addr_space omap44xx_fdif_addrs[] = { + { + .pa_start = 0x4a10a000, + .pa_end = 0x4a10a1ff, + .flags = ADDR_TYPE_RT + }, +}; + +/* l4_cfg -> fdif */ +static struct omap_hwmod_ocp_if omap44xx_l3_main_2__fdif = { + .master = &omap44xx_l3_main_2_hwmod, + .slave = &omap44xx_fdif_hwmod, + .clk = "l3_div_ck", + .addr = omap44xx_fdif_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_fdif_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* fdif slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_fdif_slaves[] = { + &omap44xx_l3_main_2__fdif, +}; + +static struct omap_hwmod omap44xx_fdif_hwmod = { + .name = "fdif", + .class = &omap44xx_fdif_hwmod_class, + .mpu_irqs = omap44xx_fdif_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_fdif_irqs), + .main_clk = "fdif_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_CAM_FDIF_CLKCTRL, + }, + }, + .slaves = omap44xx_fdif_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_fdif_slaves), + .masters = omap44xx_fdif_masters, + .masters_cnt = ARRAY_SIZE(omap44xx_fdif_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -1745,15 +2483,37 @@ static struct omap_hwmod_opt_clk gpio1_opt_clks[] = { { .role = "dbclk", .clk = "gpio1_dbclk" }, }; -static struct omap_hwmod omap44xx_gpio1_hwmod = { +static struct omap_hwmod omap443x_gpio1_hwmod = { + .name = "gpio1", + .class = &omap44xx_gpio_hwmod_class, + .mpu_irqs = omap44xx_gpio1_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_gpio1_irqs), + .main_clk = "gpio1_ick", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_WKUP_GPIO1_CLKCTRL, + .context_reg = OMAP4430_RM_WKUP_GPIO1_CONTEXT, + }, + }, + .opt_clks = gpio1_opt_clks, + .opt_clks_cnt = ARRAY_SIZE(gpio1_opt_clks), + .dev_attr = &gpio_dev_attr, + .slaves = omap44xx_gpio1_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_gpio1_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP443X), +}; + +static struct omap_hwmod omap446x_gpio1_hwmod = { .name = "gpio1", .class = &omap44xx_gpio_hwmod_class, + .flags = HWMOD_INIT_NO_RESET, .mpu_irqs = omap44xx_gpio1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_gpio1_irqs), .main_clk = "gpio1_ick", .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_WKUP_GPIO1_CLKCTRL, + .context_reg = OMAP4430_RM_WKUP_GPIO1_CONTEXT, }, }, .opt_clks = gpio1_opt_clks, @@ -1761,7 +2521,7 @@ static struct omap_hwmod omap44xx_gpio1_hwmod = { .dev_attr = &gpio_dev_attr, .slaves = omap44xx_gpio1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_gpio1_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP446X), }; /* gpio2 */ @@ -1807,6 +2567,7 @@ static struct omap_hwmod omap44xx_gpio2_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_GPIO2_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_GPIO2_CONTEXT, }, }, .opt_clks = gpio2_opt_clks, @@ -1814,7 +2575,7 @@ static struct omap_hwmod omap44xx_gpio2_hwmod = { .dev_attr = &gpio_dev_attr, .slaves = omap44xx_gpio2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_gpio2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* gpio3 */ @@ -1860,6 +2621,7 @@ static struct omap_hwmod omap44xx_gpio3_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_GPIO3_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_GPIO3_CONTEXT, }, }, .opt_clks = gpio3_opt_clks, @@ -1867,7 +2629,7 @@ static struct omap_hwmod omap44xx_gpio3_hwmod = { .dev_attr = &gpio_dev_attr, .slaves = omap44xx_gpio3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_gpio3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* gpio4 */ @@ -1913,6 +2675,7 @@ static struct omap_hwmod omap44xx_gpio4_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_GPIO4_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_GPIO4_CONTEXT, }, }, .opt_clks = gpio4_opt_clks, @@ -1920,7 +2683,7 @@ static struct omap_hwmod omap44xx_gpio4_hwmod = { .dev_attr = &gpio_dev_attr, .slaves = omap44xx_gpio4_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_gpio4_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* gpio5 */ @@ -1966,6 +2729,7 @@ static struct omap_hwmod omap44xx_gpio5_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_GPIO5_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_GPIO5_CONTEXT, }, }, .opt_clks = gpio5_opt_clks, @@ -1973,7 +2737,7 @@ static struct omap_hwmod omap44xx_gpio5_hwmod = { .dev_attr = &gpio_dev_attr, .slaves = omap44xx_gpio5_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_gpio5_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* gpio6 */ @@ -2019,6 +2783,7 @@ static struct omap_hwmod omap44xx_gpio6_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_GPIO6_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_GPIO6_CONTEXT, }, }, .opt_clks = gpio6_opt_clks, @@ -2026,7 +2791,45 @@ static struct omap_hwmod omap44xx_gpio6_hwmod = { .dev_attr = &gpio_dev_attr, .slaves = omap44xx_gpio6_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_gpio6_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* + * 'gpu' class + * 2d/3d graphics accelerator + */ + +static struct omap_hwmod_class_sysconfig omap44xx_gpu_sysc = { + .rev_offs = 0xfe00, + .sysc_offs = 0xfe10, + .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO | + MSTANDBY_SMART | MSTANDBY_SMART_WKUP), + .sysc_fields = &omap_hwmod_sysc_type2, +}; + +static struct omap_hwmod_class omap44xx_gpu_hwmod_class = { + .name = "gpu", + .sysc = &omap44xx_gpu_sysc, +}; + +/* gpu */ +static struct omap_hwmod_irq_info omap44xx_gpu_irqs[] = { + { .irq = 21 + OMAP44XX_IRQ_GIC_START }, +}; + +/* gpu master ports */ +static struct omap_hwmod_ocp_if *omap44xx_gpu_masters[] = { + &omap44xx_gpu__l3_main_2, +}; + +static struct omap_hwmod_addr_space omap44xx_gpu_addrs[] = { + { + .pa_start = 0x56000000, + .pa_end = 0x5600ffff, + .flags = ADDR_TYPE_RT + }, }; /* @@ -2044,7 +2847,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_hsi_sysc = { SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO | - MSTANDBY_SMART), + MSTANDBY_SMART | MSTANDBY_SMART_WKUP), .sysc_fields = &omap_hwmod_sysc_type1, }; @@ -2103,7 +2906,41 @@ static struct omap_hwmod omap44xx_hsi_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_hsi_slaves), .masters = omap44xx_hsi_masters, .masters_cnt = ARRAY_SIZE(omap44xx_hsi_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* l3_main_2 -> gpu */ +static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpu = { + .master = &omap44xx_l3_main_2_hwmod, + .slave = &omap44xx_gpu_hwmod, + .clk = "l3_div_ck", + .addr = omap44xx_gpu_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_gpu_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* gpu slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_gpu_slaves[] = { + &omap44xx_l3_main_2__gpu, +}; + +static struct omap_hwmod omap44xx_gpu_hwmod = { + .name = "gpu", + .class = &omap44xx_gpu_hwmod_class, + .mpu_irqs = omap44xx_gpu_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_gpu_irqs), + .main_clk = "gpu_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_GFX_GFX_CLKCTRL, + }, + }, + .slaves = omap44xx_gpu_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_gpu_slaves), + .masters = omap44xx_gpu_masters, + .masters_cnt = ARRAY_SIZE(omap44xx_gpu_masters), + .dev_attr = &smartreflex_core_dev_attr, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -2177,7 +3014,7 @@ static struct omap_hwmod omap44xx_i2c1_hwmod = { }, .slaves = omap44xx_i2c1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_i2c1_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* i2c2 */ @@ -2230,7 +3067,7 @@ static struct omap_hwmod omap44xx_i2c2_hwmod = { }, .slaves = omap44xx_i2c2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_i2c2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* i2c3 */ @@ -2283,7 +3120,7 @@ static struct omap_hwmod omap44xx_i2c3_hwmod = { }, .slaves = omap44xx_i2c3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_i2c3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* i2c4 */ @@ -2336,7 +3173,7 @@ static struct omap_hwmod omap44xx_i2c4_hwmod = { }, .slaves = omap44xx_i2c4_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_i2c4_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -2365,6 +3202,14 @@ static struct omap_hwmod_rst_info omap44xx_ipu_resets[] = { { .name = "mmu_cache", .rst_shift = 2 }, }; +static struct omap_hwmod_addr_space omap44xx_ipu_addrs[] = { + { + .pa_start = 0x55082000, + .pa_end = 0x550820ff, + .flags = ADDR_TYPE_RT + }, +}; + /* ipu master ports */ static struct omap_hwmod_ocp_if *omap44xx_ipu_masters[] = { &omap44xx_ipu__l3_main_2, @@ -2375,6 +3220,8 @@ static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ipu = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_ipu_hwmod, .clk = "l3_div_ck", + .addr = omap44xx_ipu_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_ipu_addrs), .user = OCP_USER_MPU | OCP_USER_SDMA, }; @@ -2395,7 +3242,7 @@ static struct omap_hwmod omap44xx_ipu_c0_hwmod = { .rstctrl_reg = OMAP4430_RM_DUCATI_RSTCTRL, }, }, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* Pseudo hwmod for reset control purpose only */ @@ -2410,12 +3257,13 @@ static struct omap_hwmod omap44xx_ipu_c1_hwmod = { .rstctrl_reg = OMAP4430_RM_DUCATI_RSTCTRL, }, }, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct omap_hwmod omap44xx_ipu_hwmod = { .name = "ipu", .class = &omap44xx_ipu_hwmod_class, + .flags = HWMOD_INIT_NO_RESET, .mpu_irqs = omap44xx_ipu_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_ipu_irqs), .rst_lines = omap44xx_ipu_resets, @@ -2431,7 +3279,7 @@ static struct omap_hwmod omap44xx_ipu_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_ipu_slaves), .masters = omap44xx_ipu_masters, .masters_cnt = ARRAY_SIZE(omap44xx_ipu_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -2442,6 +3290,15 @@ static struct omap_hwmod omap44xx_ipu_hwmod = { static struct omap_hwmod_class_sysconfig omap44xx_iss_sysc = { .rev_offs = 0x0000, .sysc_offs = 0x0010, + /* + * ISS needs 100 OCP clk cycles delay after a softreset before + * accessing sysconfig again. + * The lowest frequency at the moment for L3 bus is 100 MHz, so + * 1usec delay is needed. Add an x2 margin to be safe (2 usecs). + * + * TODO: Indicate errata when available. + */ + .srst_udelay = 2, .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | @@ -2518,7 +3375,7 @@ static struct omap_hwmod omap44xx_iss_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_iss_slaves), .masters = omap44xx_iss_masters, .masters_cnt = ARRAY_SIZE(omap44xx_iss_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -2549,8 +3406,16 @@ static struct omap_hwmod_rst_info omap44xx_iva_seq1_resets[] = { { .name = "seq1", .rst_shift = 1 }, }; +/* iva -> sl2if */ +static struct omap_hwmod_ocp_if omap44xx_iva__sl2if = { + .master = &omap44xx_iva_hwmod, + .slave = &omap44xx_sl2if_hwmod, + .clk = "dpll_iva_m5x2_ck", +}; + /* iva master ports */ static struct omap_hwmod_ocp_if *omap44xx_iva_masters[] = { + &omap44xx_iva__sl2if, &omap44xx_iva__l3_main_2, &omap44xx_iva__l3_instr, }; @@ -2591,7 +3456,7 @@ static struct omap_hwmod omap44xx_iva_seq0_hwmod = { .rstctrl_reg = OMAP4430_RM_IVAHD_RSTCTRL, }, }, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* Pseudo hwmod for reset control purpose only */ @@ -2606,7 +3471,7 @@ static struct omap_hwmod omap44xx_iva_seq1_hwmod = { .rstctrl_reg = OMAP4430_RM_IVAHD_RSTCTRL, }, }, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static struct omap_hwmod omap44xx_iva_hwmod = { @@ -2627,7 +3492,46 @@ static struct omap_hwmod omap44xx_iva_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_iva_slaves), .masters = omap44xx_iva_masters, .masters_cnt = ARRAY_SIZE(omap44xx_iva_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* + * 'sl2if' class + * shared level 2 memory interface + */ + +static struct omap_hwmod_class omap44xx_sl2if_hwmod_class = { + .name = "sl2if", +}; + +/* sl2if */ +/* l3_main_2 -> sl2if */ +static struct omap_hwmod_ocp_if omap44xx_l3_main_2__sl2if = { + .master = &omap44xx_l3_main_2_hwmod, + .slave = &omap44xx_sl2if_hwmod, + .clk = "l3_div_ck", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* sl2if slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_sl2if_slaves[] = { + &omap44xx_l3_main_2__sl2if, + &omap44xx_iva__sl2if, + &omap44xx_dsp__sl2if, +}; + +static struct omap_hwmod omap44xx_sl2if_hwmod = { + .name = "sl2if", + .class = &omap44xx_sl2if_hwmod_class, + .main_clk = "sl2if_ick", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_IVAHD_SL2_CLKCTRL, + }, + }, + .slaves = omap44xx_sl2if_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_sl2if_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -2694,7 +3598,7 @@ static struct omap_hwmod omap44xx_kbd_hwmod = { }, .slaves = omap44xx_kbd_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_kbd_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -2758,7 +3662,105 @@ static struct omap_hwmod omap44xx_mailbox_hwmod = { }, .slaves = omap44xx_mailbox_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mailbox_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* + * 'mcasp' class + * multi channel audio serial port controller + */ + +static struct omap_hwmod_class_sysconfig omap44xx_mcasp_sysc = { + .sysc_offs = 0x0004, + .sysc_flags = SYSC_HAS_SIDLEMODE, + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), + .sysc_fields = &omap_hwmod_sysc_type3, +}; + +static struct omap_hwmod_class omap44xx_mcasp_hwmod_class = { + .name = "omap-mcasp-dai", + .sysc = &omap44xx_mcasp_sysc, +}; + +/* mcasp */ +static struct omap_hwmod omap44xx_mcasp_hwmod; +static struct omap_hwmod_irq_info omap44xx_mcasp_irqs[] = { + { .irq = 109 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_dma_info omap44xx_mcasp_sdma_reqs[] = { + { .name = "tx", .dma_req = 7 + OMAP44XX_DMA_REQ_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_mcasp_addrs[] = { + { + .pa_start = 0x40128000, + .pa_end = 0x40128000 + SZ_4K - 1, /* McASP CFG Port */ + .flags = ADDR_TYPE_RT + }, + { + .pa_start = 0x4012A000, + .pa_end = 0x4012A000 + SZ_4K - 1, /* McASP Data Port */ + .flags = ADDR_TYPE_RT + }, +}; + +/* l4_abe -> mcasp */ +static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcasp = { + .master = &omap44xx_l4_abe_hwmod, + .slave = &omap44xx_mcasp_hwmod, + .clk = "ocp_abe_iclk", + .addr = omap44xx_mcasp_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_mcasp_addrs), + .user = OCP_USER_MPU, +}; + +static struct omap_hwmod_addr_space omap44xx_mcasp_dma_addrs[] = { + { + .pa_start = 0x49028000, + .pa_end = 0x49028000 + SZ_4K - 1, /* McASP CFG Port */ + .flags = ADDR_TYPE_RT + }, + { + .pa_start = 0x4902A000, + .pa_end = 0x4902A000 + SZ_4K - 1, /* McASP Data Port */ + .flags = ADDR_TYPE_RT + }, +}; + +/* l4_abe -> mcasp (dma) */ +static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcasp_dma = { + .master = &omap44xx_l4_abe_hwmod, + .slave = &omap44xx_mcasp_hwmod, + .clk = "ocp_abe_iclk", + .addr = omap44xx_mcasp_dma_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_mcasp_dma_addrs), + .user = OCP_USER_SDMA, +}; + +/* mcasp1 slave ports */ +static struct omap_hwmod_ocp_if *omap44xx_mcasp_slaves[] = { + &omap44xx_l4_abe__mcasp, + &omap44xx_l4_abe__mcasp_dma, +}; + +static struct omap_hwmod omap44xx_mcasp_hwmod = { + .name = "omap-mcasp-dai", + .class = &omap44xx_mcasp_hwmod_class, + .flags = HWMOD_SWSUP_SIDLE, + .mpu_irqs = omap44xx_mcasp_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcasp_irqs), + .sdma_reqs = omap44xx_mcasp_sdma_reqs, + .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcasp_sdma_reqs), + .main_clk = "mcasp_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM1_ABE_MCASP_CLKCTRL, + }, + }, + .slaves = omap44xx_mcasp_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_mcasp_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -2783,7 +3785,8 @@ static struct omap_hwmod_class omap44xx_mcbsp_hwmod_class = { /* mcbsp1 */ static struct omap_hwmod omap44xx_mcbsp1_hwmod; static struct omap_hwmod_irq_info omap44xx_mcbsp1_irqs[] = { - { .irq = 17 + OMAP44XX_IRQ_GIC_START }, + { .name = "tx", .irq = 17 + OMAP44XX_IRQ_GIC_START }, + { .name = "rx", .irq = 0 }, }; static struct omap_hwmod_dma_info omap44xx_mcbsp1_sdma_reqs[] = { @@ -2850,13 +3853,14 @@ static struct omap_hwmod omap44xx_mcbsp1_hwmod = { }, .slaves = omap44xx_mcbsp1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp1_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mcbsp2 */ static struct omap_hwmod omap44xx_mcbsp2_hwmod; static struct omap_hwmod_irq_info omap44xx_mcbsp2_irqs[] = { - { .irq = 22 + OMAP44XX_IRQ_GIC_START }, + { .name = "tx", .irq = 22 + OMAP44XX_IRQ_GIC_START }, + { .name = "rx", .irq = 0 }, }; static struct omap_hwmod_dma_info omap44xx_mcbsp2_sdma_reqs[] = { @@ -2923,13 +3927,14 @@ static struct omap_hwmod omap44xx_mcbsp2_hwmod = { }, .slaves = omap44xx_mcbsp2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mcbsp3 */ static struct omap_hwmod omap44xx_mcbsp3_hwmod; static struct omap_hwmod_irq_info omap44xx_mcbsp3_irqs[] = { - { .irq = 23 + OMAP44XX_IRQ_GIC_START }, + { .name = "tx", .irq = 23 + OMAP44XX_IRQ_GIC_START }, + { .name = "rx", .irq = 0 }, }; static struct omap_hwmod_dma_info omap44xx_mcbsp3_sdma_reqs[] = { @@ -2996,13 +4001,14 @@ static struct omap_hwmod omap44xx_mcbsp3_hwmod = { }, .slaves = omap44xx_mcbsp3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mcbsp4 */ static struct omap_hwmod omap44xx_mcbsp4_hwmod; static struct omap_hwmod_irq_info omap44xx_mcbsp4_irqs[] = { - { .irq = 16 + OMAP44XX_IRQ_GIC_START }, + { .name = "tx", .irq = 16 + OMAP44XX_IRQ_GIC_START }, + { .name = "rx", .irq = 0 }, }; static struct omap_hwmod_dma_info omap44xx_mcbsp4_sdma_reqs[] = { @@ -3048,7 +4054,7 @@ static struct omap_hwmod omap44xx_mcbsp4_hwmod = { }, .slaves = omap44xx_mcbsp4_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp4_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -3136,11 +4142,12 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM1_ABE_PDM_CLKCTRL, + .context_reg = OMAP4430_RM_ABE_PDM_CONTEXT, }, }, .slaves = omap44xx_mcpdm_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcpdm_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -3226,7 +4233,7 @@ static struct omap_hwmod omap44xx_mcspi1_hwmod = { .dev_attr = &mcspi1_dev_attr, .slaves = omap44xx_mcspi1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi1_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mcspi2 */ @@ -3286,7 +4293,7 @@ static struct omap_hwmod omap44xx_mcspi2_hwmod = { .dev_attr = &mcspi2_dev_attr, .slaves = omap44xx_mcspi2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mcspi3 */ @@ -3346,7 +4353,7 @@ static struct omap_hwmod omap44xx_mcspi3_hwmod = { .dev_attr = &mcspi3_dev_attr, .slaves = omap44xx_mcspi3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mcspi4 */ @@ -3404,7 +4411,7 @@ static struct omap_hwmod omap44xx_mcspi4_hwmod = { .dev_attr = &mcspi4_dev_attr, .slaves = omap44xx_mcspi4_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi4_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -3419,7 +4426,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_mmc_sysc = { SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET), .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO | + MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART), .sysc_fields = &omap_hwmod_sysc_type2, }; @@ -3484,6 +4491,7 @@ static struct omap_hwmod omap44xx_mmc1_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L3INIT_MMC1_CLKCTRL, + .context_reg = OMAP4430_RM_L3INIT_MMC1_CONTEXT, }, }, .dev_attr = &mmc1_dev_attr, @@ -3491,7 +4499,7 @@ static struct omap_hwmod omap44xx_mmc1_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_mmc1_slaves), .masters = omap44xx_mmc1_masters, .masters_cnt = ARRAY_SIZE(omap44xx_mmc1_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mmc2 */ @@ -3543,13 +4551,14 @@ static struct omap_hwmod omap44xx_mmc2_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L3INIT_MMC2_CLKCTRL, + .context_reg = OMAP4430_RM_L3INIT_MMC2_CONTEXT, }, }, .slaves = omap44xx_mmc2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mmc2_slaves), .masters = omap44xx_mmc2_masters, .masters_cnt = ARRAY_SIZE(omap44xx_mmc2_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mmc3 */ @@ -3597,11 +4606,12 @@ static struct omap_hwmod omap44xx_mmc3_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD3_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_MMCSD3_CONTEXT, }, }, .slaves = omap44xx_mmc3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mmc3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mmc4 */ @@ -3649,11 +4659,12 @@ static struct omap_hwmod omap44xx_mmc4_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD4_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_MMCSD4_CONTEXT, }, }, .slaves = omap44xx_mmc4_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mmc4_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* mmc5 */ @@ -3701,215 +4712,12 @@ static struct omap_hwmod omap44xx_mmc5_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD5_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_MMCSD5_CONTEXT, }, }, .slaves = omap44xx_mmc5_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_mmc5_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), -}; - -/* - * 'mpu' class - * mpu sub-system - */ - -static struct omap_hwmod_class omap44xx_mpu_hwmod_class = { - .name = "mpu", -}; - -/* mpu */ -static struct omap_hwmod_irq_info omap44xx_mpu_irqs[] = { - { .name = "pl310", .irq = 0 + OMAP44XX_IRQ_GIC_START }, - { .name = "cti0", .irq = 1 + OMAP44XX_IRQ_GIC_START }, - { .name = "cti1", .irq = 2 + OMAP44XX_IRQ_GIC_START }, -}; - -/* mpu master ports */ -static struct omap_hwmod_ocp_if *omap44xx_mpu_masters[] = { - &omap44xx_mpu__l3_main_1, - &omap44xx_mpu__l4_abe, - &omap44xx_mpu__dmm, -}; - -static struct omap_hwmod omap44xx_mpu_hwmod = { - .name = "mpu", - .class = &omap44xx_mpu_hwmod_class, - .flags = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET), - .mpu_irqs = omap44xx_mpu_irqs, - .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mpu_irqs), - .main_clk = "dpll_mpu_m2_ck", - .prcm = { - .omap4 = { - .clkctrl_reg = OMAP4430_CM_MPU_MPU_CLKCTRL, - }, - }, - .masters = omap44xx_mpu_masters, - .masters_cnt = ARRAY_SIZE(omap44xx_mpu_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), -}; - -/* - * 'smartreflex' class - * smartreflex module (monitor silicon performance and outputs a measure of - * performance error) - */ - -/* The IP is not compliant to type1 / type2 scheme */ -static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_smartreflex = { - .sidle_shift = 24, - .enwkup_shift = 26, -}; - -static struct omap_hwmod_class_sysconfig omap44xx_smartreflex_sysc = { - .sysc_offs = 0x0038, - .sysc_flags = (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE), - .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | - SIDLE_SMART_WKUP), - .sysc_fields = &omap_hwmod_sysc_type_smartreflex, -}; - -static struct omap_hwmod_class omap44xx_smartreflex_hwmod_class = { - .name = "smartreflex", - .sysc = &omap44xx_smartreflex_sysc, - .rev = 2, -}; - -/* smartreflex_core */ -static struct omap_hwmod omap44xx_smartreflex_core_hwmod; -static struct omap_hwmod_irq_info omap44xx_smartreflex_core_irqs[] = { - { .irq = 19 + OMAP44XX_IRQ_GIC_START }, -}; - -static struct omap_hwmod_addr_space omap44xx_smartreflex_core_addrs[] = { - { - .pa_start = 0x4a0dd000, - .pa_end = 0x4a0dd03f, - .flags = ADDR_TYPE_RT - }, -}; - -/* l4_cfg -> smartreflex_core */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_core = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_smartreflex_core_hwmod, - .clk = "l4_div_ck", - .addr = omap44xx_smartreflex_core_addrs, - .addr_cnt = ARRAY_SIZE(omap44xx_smartreflex_core_addrs), - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* smartreflex_core slave ports */ -static struct omap_hwmod_ocp_if *omap44xx_smartreflex_core_slaves[] = { - &omap44xx_l4_cfg__smartreflex_core, -}; - -static struct omap_hwmod omap44xx_smartreflex_core_hwmod = { - .name = "smartreflex_core", - .class = &omap44xx_smartreflex_hwmod_class, - .mpu_irqs = omap44xx_smartreflex_core_irqs, - .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_smartreflex_core_irqs), - .main_clk = "smartreflex_core_fck", - .vdd_name = "core", - .prcm = { - .omap4 = { - .clkctrl_reg = OMAP4430_CM_ALWON_SR_CORE_CLKCTRL, - }, - }, - .slaves = omap44xx_smartreflex_core_slaves, - .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_core_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), -}; - -/* smartreflex_iva */ -static struct omap_hwmod omap44xx_smartreflex_iva_hwmod; -static struct omap_hwmod_irq_info omap44xx_smartreflex_iva_irqs[] = { - { .irq = 102 + OMAP44XX_IRQ_GIC_START }, -}; - -static struct omap_hwmod_addr_space omap44xx_smartreflex_iva_addrs[] = { - { - .pa_start = 0x4a0db000, - .pa_end = 0x4a0db03f, - .flags = ADDR_TYPE_RT - }, -}; - -/* l4_cfg -> smartreflex_iva */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_iva = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_smartreflex_iva_hwmod, - .clk = "l4_div_ck", - .addr = omap44xx_smartreflex_iva_addrs, - .addr_cnt = ARRAY_SIZE(omap44xx_smartreflex_iva_addrs), - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* smartreflex_iva slave ports */ -static struct omap_hwmod_ocp_if *omap44xx_smartreflex_iva_slaves[] = { - &omap44xx_l4_cfg__smartreflex_iva, -}; - -static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = { - .name = "smartreflex_iva", - .class = &omap44xx_smartreflex_hwmod_class, - .mpu_irqs = omap44xx_smartreflex_iva_irqs, - .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_smartreflex_iva_irqs), - .main_clk = "smartreflex_iva_fck", - .vdd_name = "iva", - .prcm = { - .omap4 = { - .clkctrl_reg = OMAP4430_CM_ALWON_SR_IVA_CLKCTRL, - }, - }, - .slaves = omap44xx_smartreflex_iva_slaves, - .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_iva_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), -}; - -/* smartreflex_mpu */ -static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod; -static struct omap_hwmod_irq_info omap44xx_smartreflex_mpu_irqs[] = { - { .irq = 18 + OMAP44XX_IRQ_GIC_START }, -}; - -static struct omap_hwmod_addr_space omap44xx_smartreflex_mpu_addrs[] = { - { - .pa_start = 0x4a0d9000, - .pa_end = 0x4a0d903f, - .flags = ADDR_TYPE_RT - }, -}; - -/* l4_cfg -> smartreflex_mpu */ -static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_mpu = { - .master = &omap44xx_l4_cfg_hwmod, - .slave = &omap44xx_smartreflex_mpu_hwmod, - .clk = "l4_div_ck", - .addr = omap44xx_smartreflex_mpu_addrs, - .addr_cnt = ARRAY_SIZE(omap44xx_smartreflex_mpu_addrs), - .user = OCP_USER_MPU | OCP_USER_SDMA, -}; - -/* smartreflex_mpu slave ports */ -static struct omap_hwmod_ocp_if *omap44xx_smartreflex_mpu_slaves[] = { - &omap44xx_l4_cfg__smartreflex_mpu, -}; - -static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = { - .name = "smartreflex_mpu", - .class = &omap44xx_smartreflex_hwmod_class, - .mpu_irqs = omap44xx_smartreflex_mpu_irqs, - .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_smartreflex_mpu_irqs), - .main_clk = "smartreflex_mpu_fck", - .vdd_name = "mpu", - .prcm = { - .omap4 = { - .clkctrl_reg = OMAP4430_CM_ALWON_SR_MPU_CLKCTRL, - }, - }, - .slaves = omap44xx_smartreflex_mpu_slaves, - .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_mpu_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -3970,7 +4778,7 @@ static struct omap_hwmod omap44xx_spinlock_hwmod = { }, .slaves = omap44xx_spinlock_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_spinlock_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -3994,6 +4802,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_timer_1ms_sysc = { static struct omap_hwmod_class omap44xx_timer_1ms_hwmod_class = { .name = "timer", .sysc = &omap44xx_timer_1ms_sysc, + .rev = OMAP_TIMER_IP_VERSION_1, }; static struct omap_hwmod_class_sysconfig omap44xx_timer_sysc = { @@ -4009,6 +4818,12 @@ static struct omap_hwmod_class_sysconfig omap44xx_timer_sysc = { static struct omap_hwmod_class omap44xx_timer_hwmod_class = { .name = "timer", .sysc = &omap44xx_timer_sysc, + .rev = OMAP_TIMER_IP_VERSION_2, +}; + +/* secure timer can assign this to .dev_attr field */ +static struct omap_secure_timer_dev_attr secure_timer_dev_attr = { + .is_secure_timer = true, }; /* timer1 */ @@ -4053,7 +4868,7 @@ static struct omap_hwmod omap44xx_timer1_hwmod = { }, .slaves = omap44xx_timer1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer1_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer2 */ @@ -4094,11 +4909,12 @@ static struct omap_hwmod omap44xx_timer2_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_DMTIMER2_CONTEXT, }, }, .slaves = omap44xx_timer2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer3 */ @@ -4139,11 +4955,12 @@ static struct omap_hwmod omap44xx_timer3_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_DMTIMER3_CONTEXT, }, }, .slaves = omap44xx_timer3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer4 */ @@ -4184,11 +5001,12 @@ static struct omap_hwmod omap44xx_timer4_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_DMTIMER4_CONTEXT, }, }, .slaves = omap44xx_timer4_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer4_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer5 */ @@ -4248,11 +5066,12 @@ static struct omap_hwmod omap44xx_timer5_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL, + .context_reg = OMAP4430_RM_ABE_TIMER5_CONTEXT, }, }, .slaves = omap44xx_timer5_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer5_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer6 */ @@ -4312,11 +5131,12 @@ static struct omap_hwmod omap44xx_timer6_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL, + .context_reg = OMAP4430_RM_ABE_TIMER6_CONTEXT, }, }, .slaves = omap44xx_timer6_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer6_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer7 */ @@ -4376,11 +5196,12 @@ static struct omap_hwmod omap44xx_timer7_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL, + .context_reg = OMAP4430_RM_ABE_TIMER7_CONTEXT, }, }, .slaves = omap44xx_timer7_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer7_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer8 */ @@ -4440,11 +5261,12 @@ static struct omap_hwmod omap44xx_timer8_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL, + .context_reg = OMAP4430_RM_ABE_TIMER8_CONTEXT, }, }, .slaves = omap44xx_timer8_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer8_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer9 */ @@ -4485,11 +5307,12 @@ static struct omap_hwmod omap44xx_timer9_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_DMTIMER9_CONTEXT, }, }, .slaves = omap44xx_timer9_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer9_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer10 */ @@ -4530,11 +5353,12 @@ static struct omap_hwmod omap44xx_timer10_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_DMTIMER10_CONTEXT, }, }, .slaves = omap44xx_timer10_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer10_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* timer11 */ @@ -4575,11 +5399,12 @@ static struct omap_hwmod omap44xx_timer11_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_DMTIMER11_CONTEXT, }, }, .slaves = omap44xx_timer11_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_timer11_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -4641,6 +5466,7 @@ static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = { static struct omap_hwmod omap44xx_uart1_hwmod = { .name = "uart1", .class = &omap44xx_uart_hwmod_class, + .flags = HWMOD_SWSUP_SIDLE, .mpu_irqs = omap44xx_uart1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_uart1_irqs), .sdma_reqs = omap44xx_uart1_sdma_reqs, @@ -4649,11 +5475,12 @@ static struct omap_hwmod omap44xx_uart1_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_UART1_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_UART1_CONTEXT, }, }, .slaves = omap44xx_uart1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_uart1_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* uart2 */ @@ -4701,11 +5528,12 @@ static struct omap_hwmod omap44xx_uart2_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_UART2_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_UART2_CONTEXT, }, }, .slaves = omap44xx_uart2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_uart2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* uart3 */ @@ -4754,11 +5582,12 @@ static struct omap_hwmod omap44xx_uart3_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_UART3_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_UART3_CONTEXT, }, }, .slaves = omap44xx_uart3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_uart3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* uart4 */ @@ -4806,11 +5635,12 @@ static struct omap_hwmod omap44xx_uart4_hwmod = { .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_L4PER_UART4_CLKCTRL, + .context_reg = OMAP4430_RM_L4PER_UART4_CONTEXT, }, }, .slaves = omap44xx_uart4_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_uart4_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -4892,7 +5722,7 @@ static struct omap_hwmod omap44xx_usb_otg_hs_hwmod = { .slaves_cnt = ARRAY_SIZE(omap44xx_usb_otg_hs_slaves), .masters = omap44xx_usb_otg_hs_masters, .masters_cnt = ARRAY_SIZE(omap44xx_usb_otg_hs_masters), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* @@ -4960,7 +5790,7 @@ static struct omap_hwmod omap44xx_wd_timer2_hwmod = { }, .slaves = omap44xx_wd_timer2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_wd_timer2_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; /* wd_timer3 */ @@ -5024,7 +5854,235 @@ static struct omap_hwmod omap44xx_wd_timer3_hwmod = { }, .slaves = omap44xx_wd_timer3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_wd_timer3_slaves), - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* + * 'usb_host_hs' class + * high-speed multi-port usb host controller + */ +static struct omap_hwmod_ocp_if omap44xx_usb_host_hs__l3_main_2 = { + .master = &omap44xx_usb_host_hs_hwmod, + .slave = &omap44xx_l3_main_2_hwmod, + .clk = "l3_div_ck", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_class_sysconfig omap44xx_usb_host_hs_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + .syss_offs = 0x0014, + .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART | + MSTANDBY_SMART_WKUP), + .sysc_fields = &omap_hwmod_sysc_type2, +}; + +static struct omap_hwmod_class omap44xx_usb_host_hs_hwmod_class = { + .name = "usbhs_uhh", + .sysc = &omap44xx_usb_host_hs_sysc, +}; + +static struct omap_hwmod_ocp_if *omap44xx_usb_host_hs_masters[] = { + &omap44xx_usb_host_hs__l3_main_2, +}; + +static struct omap_hwmod_addr_space omap44xx_usb_host_hs_addrs[] = { + { + .name = "uhh", + .pa_start = 0x4a064000, + .pa_end = 0x4a0647ff, + .flags = ADDR_TYPE_RT + }, +}; + +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_hs = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_usb_host_hs_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_usb_host_hs_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if *omap44xx_usb_host_hs_slaves[] = { + &omap44xx_l4_cfg__usb_host_hs, +}; + +static struct omap_hwmod omap44xx_usb_host_hs_hwmod = { + .name = "usbhs_uhh", + .class = &omap44xx_usb_host_hs_hwmod_class, + .main_clk = "usb_host_hs_fck", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, + }, + }, + .slaves = omap44xx_usb_host_hs_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_slaves), + .masters = omap44xx_usb_host_hs_masters, + .masters_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_masters), + .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), +}; + +/* 'usbhs_ohci' class */ +static struct omap_hwmod_class omap44xx_usbhs_ohci_hwmod_class = { + .name = "usbhs_ohci", +}; + +static struct omap_hwmod_irq_info omap44xx_usbhs_ohci_irqs[] = { + { .name = "ohci-irq", .irq = 76 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_usbhs_ohci_addrs[] = { + { + .name = "ohci", + .pa_start = 0x4A064800, + .pa_end = 0x4A064BFF, + .flags = ADDR_MAP_ON_INIT + } +}; + +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usbhs_ohci = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_usbhs_ohci_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_usbhs_ohci_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_usbhs_ohci_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if *omap44xx_usbhs_ohci_slaves[] = { + &omap44xx_l4_cfg__usbhs_ohci, +}; + +static struct omap_hwmod_ocp_if *omap44xx_usbhs_ohci_masters[] = { + &omap44xx_usb_host_hs__l3_main_2, +}; + +static struct omap_hwmod omap44xx_usbhs_ohci_hwmod = { + .name = "usbhs_ohci", + .class = &omap44xx_usbhs_ohci_hwmod_class, + .mpu_irqs = omap44xx_usbhs_ohci_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_usbhs_ohci_irqs), + .slaves = omap44xx_usbhs_ohci_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_usbhs_ohci_slaves), + .masters = omap44xx_usbhs_ohci_masters, + .masters_cnt = ARRAY_SIZE(omap44xx_usbhs_ohci_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .flags = HWMOD_INIT_NO_RESET | HWMOD_NO_IDLEST, +}; + +/* 'usbhs_ehci' class */ +static struct omap_hwmod_class omap44xx_usbhs_ehci_hwmod_class = { + .name = "usbhs_ehci", +}; + +static struct omap_hwmod_irq_info omap44xx_usbhs_ehci_irqs[] = { + { .name = "ehci-irq", .irq = 77 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_usbhs_ehci_addrs[] = { + { + .name = "ehci", + .pa_start = 0x4A064C00, + .pa_end = 0x4A064FFF, + .flags = ADDR_MAP_ON_INIT + } +}; + +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usbhs_ehci = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_usbhs_ehci_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_usbhs_ehci_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_usbhs_ehci_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if *omap44xx_usbhs_ehci_slaves[] = { + &omap44xx_l4_cfg__usbhs_ehci, +}; + +static struct omap_hwmod_ocp_if *omap44xx_usbhs_ehci_masters[] = { + &omap44xx_usb_host_hs__l3_main_2, +}; + + +static struct omap_hwmod omap44xx_usbhs_ehci_hwmod = { + .name = "usbhs_ehci", + .class = &omap44xx_usbhs_ehci_hwmod_class, + .mpu_irqs = omap44xx_usbhs_ehci_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_usbhs_ehci_irqs), + .slaves = omap44xx_usbhs_ehci_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_usbhs_ehci_slaves), + .masters = omap44xx_usbhs_ehci_masters, + .masters_cnt = ARRAY_SIZE(omap44xx_usbhs_ehci_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .flags = HWMOD_INIT_NO_RESET | HWMOD_NO_IDLEST, +}; + +/* + * 'usb_tll_hs' class + * usb_tll_hs module is the adapter on the usb_host_hs ports + */ +static struct omap_hwmod_class_sysconfig omap44xx_usb_tll_hs_sysc = { + .rev_offs = 0x0000, + .sysc_offs = 0x0010, + .syss_offs = 0x0014, + .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE), + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class omap44xx_usb_tll_hs_hwmod_class = { + .name = "usbhs_tll", + .sysc = &omap44xx_usb_tll_hs_sysc, +}; + +static struct omap_hwmod_irq_info omap44xx_usb_tll_hs_irqs[] = { + { .name = "tll-irq", .irq = 78 + OMAP44XX_IRQ_GIC_START }, +}; + +static struct omap_hwmod_addr_space omap44xx_usb_tll_hs_addrs[] = { + { + .name = "tll", + .pa_start = 0x4a062000, + .pa_end = 0x4a063fff, + .flags = ADDR_TYPE_RT + }, +}; + +static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_tll_hs = { + .master = &omap44xx_l4_cfg_hwmod, + .slave = &omap44xx_usb_tll_hs_hwmod, + .clk = "l4_div_ck", + .addr = omap44xx_usb_tll_hs_addrs, + .addr_cnt = ARRAY_SIZE(omap44xx_usb_tll_hs_addrs), + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +static struct omap_hwmod_ocp_if *omap44xx_usb_tll_hs_slaves[] = { + &omap44xx_l4_cfg__usb_tll_hs, +}; + +static struct omap_hwmod omap44xx_usb_tll_hs_hwmod = { + .name = "usbhs_tll", + .class = &omap44xx_usb_tll_hs_hwmod_class, + .mpu_irqs = omap44xx_usb_tll_hs_irqs, + .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_usb_tll_hs_irqs), + .main_clk = "usb_tll_hs_ick", + .prcm = { + .omap4 = { + .clkctrl_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, + }, + }, + .slaves = omap44xx_usb_tll_hs_slaves, + .slaves_cnt = ARRAY_SIZE(omap44xx_usb_tll_hs_slaves), + .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), }; static __initdata struct omap_hwmod *omap44xx_hwmods[] = { @@ -5051,10 +6109,11 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = { &omap44xx_mpu_private_hwmod, /* aess class */ -/* &omap44xx_aess_hwmod, */ + &omap44xx_aess_hwmod, /* bandgap class */ - &omap44xx_bandgap_hwmod, + &omap443x_bandgap_hwmod, + &omap446x_bandgap_hwmod, /* counter class */ /* &omap44xx_counter_32k_hwmod, */ @@ -5078,8 +6137,13 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = { &omap44xx_dss_rfbi_hwmod, &omap44xx_dss_venc_hwmod, + /* emif class */ + &omap44xx_emif1_hwmod, + &omap44xx_emif2_hwmod, + /* gpio class */ - &omap44xx_gpio1_hwmod, + &omap443x_gpio1_hwmod, + &omap446x_gpio1_hwmod, &omap44xx_gpio2_hwmod, &omap44xx_gpio3_hwmod, &omap44xx_gpio4_hwmod, @@ -5087,7 +6151,10 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = { &omap44xx_gpio6_hwmod, /* hsi class */ -/* &omap44xx_hsi_hwmod, */ + &omap44xx_hsi_hwmod, + + /* gpu class */ + &omap44xx_gpu_hwmod, /* i2c class */ &omap44xx_i2c1_hwmod, @@ -5101,19 +6168,28 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = { &omap44xx_ipu_c1_hwmod, /* iss class */ -/* &omap44xx_iss_hwmod, */ + &omap44xx_iss_hwmod, + + /* fdif class */ + &omap44xx_fdif_hwmod, /* iva class */ &omap44xx_iva_hwmod, &omap44xx_iva_seq0_hwmod, &omap44xx_iva_seq1_hwmod, + /* sl2if class */ + &omap44xx_sl2if_hwmod, + /* kbd class */ &omap44xx_kbd_hwmod, /* mailbox class */ &omap44xx_mailbox_hwmod, + /* mcasp class */ + &omap44xx_mcasp_hwmod, + /* mcbsp class */ &omap44xx_mcbsp1_hwmod, &omap44xx_mcbsp2_hwmod, @@ -5121,7 +6197,7 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = { &omap44xx_mcbsp4_hwmod, /* mcpdm class */ -/* &omap44xx_mcpdm_hwmod, */ + &omap44xx_mcpdm_hwmod, /* mcspi class */ &omap44xx_mcspi1_hwmod, @@ -5160,6 +6236,12 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = { &omap44xx_timer10_hwmod, &omap44xx_timer11_hwmod, + /* ctrl module class */ + &omap44xx_ctrl_module_core_hwmod, + + /* thermal sensor hwmod */ + &omap44xx_thermal_sensor_hwmod, + /* uart class */ &omap44xx_uart1_hwmod, &omap44xx_uart2_hwmod, @@ -5173,6 +6255,10 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = { &omap44xx_wd_timer2_hwmod, &omap44xx_wd_timer3_hwmod, + &omap44xx_usb_host_hs_hwmod, + &omap44xx_usbhs_ohci_hwmod, + &omap44xx_usbhs_ehci_hwmod, + &omap44xx_usb_tll_hs_hwmod, NULL, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.c b/arch/arm/mach-omap2/omap_hwmod_common_data.c index 08a1342..0312771 100644 --- a/arch/arm/mach-omap2/omap_hwmod_common_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_common_data.c @@ -49,6 +49,15 @@ struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2 = { .srst_shift = SYSC_TYPE2_SOFTRESET_SHIFT, }; +/** + * struct omap_hwmod_sysc_type3 - TYPE3 sysconfig scheme. + * + * To be used by hwmod structure to specify the sysconfig offsets if the + * device ip is compliant only implements the sidle feature. + */ +struct omap_hwmod_sysc_fields omap_hwmod_sysc_type3 = { + .sidle_shift = SYSC_TYPE3_SIDLEMODE_SHIFT, +}; /* * omap_hwmod class data diff --git a/arch/arm/mach-omap2/omap_l3_noc.c b/arch/arm/mach-omap2/omap_l3_noc.c index 7b9f190..9d152de 100644 --- a/arch/arm/mach-omap2/omap_l3_noc.c +++ b/arch/arm/mach-omap2/omap_l3_noc.c @@ -29,6 +29,29 @@ #include "omap_l3_noc.h" +#define NUM_OF_L3_MASTERS ARRAY_SIZE(l3_masters) + +static void l3_dump_targ_context(u32 baseaddr) +{ + pr_err("COREREG : 0x%08x\n", readl(baseaddr + L3_COREREG)); + pr_err("VERSIONREG : 0x%08x\n", readl(baseaddr + L3_VERSIONREG)); + pr_err("MAINCTLREG : 0x%08x\n", readl(baseaddr + L3_MAINCTLREG)); + pr_err("NTTPADDR_0 : 0x%08x\n", readl(baseaddr + L3_NTTPADDR_0)); + pr_err("SVRTSTDLVL : 0x%08x\n", readl(baseaddr + L3_SVRTSTDLVL)); + pr_err("SVRTCUSTOMLVL: 0x%08x\n", readl(baseaddr + L3_SVRTCUSTOMLVL)); + pr_err("MAIN : 0x%08x\n", readl(baseaddr + L3_MAIN)); + pr_err("HDR : 0x%08x\n", readl(baseaddr + L3_HDR)); + pr_err("MSTADDR : 0x%08x\n", readl(baseaddr + L3_MSTADDR)); + pr_err("SLVADDR : 0x%08x\n", readl(baseaddr + L3_SLVADDR)); + pr_err("INFO : 0x%08x\n", readl(baseaddr + L3_INFO)); + pr_err("SLVOFSLSB : 0x%08x\n", readl(baseaddr + L3_SLVOFSLSB)); + pr_err("SLVOFSMSB : 0x%08x\n", readl(baseaddr + L3_SLVOFSMSB)); + pr_err("CUSTOMINFO_INFO : 0x%08x\n", readl(baseaddr + L3_CUSTOMINFO_INFO)); + pr_err("CUSTOMINFO_MSTADDR: 0x%08x\n", readl(baseaddr + L3_CUSTOMINFO_MSTADDR)); + pr_err("CUSTOMINFO_OPCODE : 0x%08x\n", readl(baseaddr + L3_CUSTOMINFO_OPCODE)); + pr_err("ADDRSPACESIZELOG : 0x%08x\n", readl(baseaddr + L3_ADDRSPACESIZELOG)); +} + /* * Interrupt Handler for L3 error detection. * 1) Identify the L3 clockdomain partition to which the error belongs to. @@ -56,10 +79,10 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) { struct omap4_l3 *l3 = _l3; - int inttype, i, j; + int inttype, i, j, k; int err_src = 0; u32 std_err_main_addr, std_err_main, err_reg; - u32 base, slave_addr, clear; + u32 base, slave_addr, clear, regoffset, masterid; char *source_name; /* Get the Type of interrupt */ @@ -88,11 +111,16 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) case STANDARD_ERROR: source_name = l3_targ_stderrlog_main_name[i][err_src]; + regoffset = targ_reg_offset[i][err_src]; slave_addr = std_err_main_addr + L3_SLAVE_ADDRESS_OFFSET; + WARN(true, "L3 standard error: SOURCE:%s at address 0x%x\n", source_name, readl(slave_addr)); + + l3_dump_targ_context(base + regoffset); + /* clear the std error log*/ clear = std_err_main | CLEAR_STDERR_LOG; writel(clear, std_err_main_addr); @@ -101,9 +129,29 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) case CUSTOM_ERROR: source_name = l3_targ_stderrlog_main_name[i][err_src]; + regoffset = targ_reg_offset[i][err_src]; WARN(true, "CUSTOM SRESP error with SOURCE:%s\n", source_name); + + masterid = readl(base + regoffset + + L3_CUSTOMINFO_MSTADDR); + + for (k = 0; + k < NUM_OF_L3_MASTERS; + k++) { + if (masterid == l3_masters[k].id) { + pr_err("Master 0x%x %10s\n", + masterid, + l3_masters[k].name); + pr_err("%s OPCODE 0x%08x\n", + source_name, + readl(base + regoffset + + L3_CUSTOMINFO_OPCODE)); + break; + } + } + /* clear the std error log*/ clear = std_err_main | CLEAR_STDERR_LOG; writel(clear, std_err_main_addr); diff --git a/arch/arm/mach-omap2/omap_l3_noc.h b/arch/arm/mach-omap2/omap_l3_noc.h index 359b833..56d6b0a 100644 --- a/arch/arm/mach-omap2/omap_l3_noc.h +++ b/arch/arm/mach-omap2/omap_l3_noc.h @@ -37,6 +37,24 @@ #define L3_APPLICATION_ERROR 0x0 #define L3_DEBUG_ERROR 0x1 +#define L3_COREREG 0x00 +#define L3_VERSIONREG 0x04 +#define L3_MAINCTLREG 0x08 +#define L3_NTTPADDR_0 0x10 +#define L3_SVRTSTDLVL 0x40 +#define L3_SVRTCUSTOMLVL 0x44 +#define L3_MAIN 0x48 +#define L3_HDR 0x4C +#define L3_MSTADDR 0x50 +#define L3_SLVADDR 0x54 +#define L3_INFO 0x58 +#define L3_SLVOFSLSB 0x5C +#define L3_SLVOFSMSB 0x60 +#define L3_CUSTOMINFO_INFO 0x64 +#define L3_CUSTOMINFO_MSTADDR 0x68 +#define L3_CUSTOMINFO_OPCODE 0x6C +#define L3_ADDRSPACESIZELOG 0x80 + u32 l3_flagmux[L3_MODULES] = { 0x50C, 0x100C, @@ -79,6 +97,34 @@ u32 l3_targ_stderrlog_main_clk3[] = { 0x0148 /* EMUSS */ }; +struct l3_masters_data { + u32 id; + char name[15]; +}; + +struct l3_masters_data l3_masters[] = { + { 0x0 , "MPU"}, + { 0x10, "CS_ADP"}, + { 0x14, "Unknown"}, + { 0x20, "DSP"}, + { 0x30, "IVAHD"}, + { 0x40, "ISS"}, + { 0x44, "DucatiM3"}, + { 0x48, "FaceDetect"}, + { 0x50, "SDMA_Rd"}, + { 0x54, "SDMA_Wr"}, + { 0x58, "Unknown"}, + { 0x5C, "Unknown"}, + { 0x60, "SGX"}, + { 0x70, "DSS"}, + { 0x80, "C2C"}, + { 0x88, "Unknown"}, + { 0x8C, "Unknown"}, + { 0x90, "HSI"}, + { 0xA0, "MMC1"}, + { 0xA4, "MMC2"}, +}; + char *l3_targ_stderrlog_main_name[L3_MODULES][18] = { { "DMM1", @@ -112,6 +158,39 @@ char *l3_targ_stderrlog_main_name[L3_MODULES][18] = { }, }; +u32 targ_reg_offset[L3_MODULES][18] = { + { + 0x100, + 0x200, + 0x300, + 0x400, + 0x0, + }, + { + 0x500, + 0x300, + 0x100, + 0x400, + 0x700, + 0x000, + 0x000, + 0x000, + 0x000, + 0x600, + 0x800, + 0x000, + 0x000, + 0x000, + 0x000, + 0x100, + 0xA00, + 0xB00, + }, + { + 0x000000 + }, +}; + u32 *l3_targ[L3_MODULES] = { l3_targ_stderrlog_main_clk1, l3_targ_stderrlog_main_clk2, diff --git a/arch/arm/mach-omap2/omap_opp_data.h b/arch/arm/mach-omap2/omap_opp_data.h index c784c12..37d16e1 100644 --- a/arch/arm/mach-omap2/omap_opp_data.h +++ b/arch/arm/mach-omap2/omap_opp_data.h @@ -49,6 +49,8 @@ */ struct omap_opp_def { char *hwmod_name; + char *voltdm_name; + char *clk_name; unsigned long freq; unsigned long u_volt; @@ -59,9 +61,11 @@ struct omap_opp_def { /* * Initialization wrapper used to define an OPP for OMAP variants. */ -#define OPP_INITIALIZER(_hwmod_name, _enabled, _freq, _uv) \ +#define OPP_INITIALIZER(_hwmod_name, _clk_name, _voltdm_name, _enabled, _freq, _uv) \ { \ .hwmod_name = _hwmod_name, \ + .clk_name = _clk_name, \ + .voltdm_name = _voltdm_name, \ .default_available = _enabled, \ .freq = _freq, \ .u_volt = _uv, \ @@ -71,12 +75,14 @@ struct omap_opp_def { * Initialization wrapper used to define SmartReflex process data * XXX Is this needed? Just use C99 initializers in data files? */ -#define VOLT_DATA_DEFINE(_v_nom, _efuse_offs, _errminlimit, _errgain) \ +#define VOLT_DATA_DEFINE(_v_nom, _v_margin, _efuse_offs, _errminlimit, _errgain, _abb_type) \ { \ .volt_nominal = _v_nom, \ + .volt_margin = _v_margin, \ .sr_efuse_offs = _efuse_offs, \ .sr_errminlimit = _errminlimit, \ - .vp_errgain = _errgain \ + .vp_errgain = _errgain, \ + .abb_type = _abb_type, \ } /* Use this to initialize the default table */ @@ -86,11 +92,21 @@ extern int __init omap_init_opp_table(struct omap_opp_def *opp_def, extern struct omap_volt_data omap34xx_vddmpu_volt_data[]; extern struct omap_volt_data omap34xx_vddcore_volt_data[]; +extern struct omap_vdd_dep_info omap34xx_vddmpu_dep_info[]; extern struct omap_volt_data omap36xx_vddmpu_volt_data[]; extern struct omap_volt_data omap36xx_vddcore_volt_data[]; +extern struct omap_vdd_dep_info omap36xx_vddmpu_dep_info[]; -extern struct omap_volt_data omap44xx_vdd_mpu_volt_data[]; -extern struct omap_volt_data omap44xx_vdd_iva_volt_data[]; -extern struct omap_volt_data omap44xx_vdd_core_volt_data[]; +extern struct omap_volt_data omap443x_vdd_mpu_volt_data[]; +extern struct omap_volt_data omap443x_vdd_iva_volt_data[]; +extern struct omap_volt_data omap443x_vdd_core_volt_data[]; +extern struct omap_volt_data omap446x_vdd_mpu_volt_data[]; +extern struct omap_volt_data omap446x_vdd_iva_volt_data[]; +extern struct omap_volt_data omap446x_vdd_core_volt_data[]; + +extern struct omap_vdd_dep_info omap443x_vddmpu_dep_info[]; +extern struct omap_vdd_dep_info omap443x_vddiva_dep_info[]; +extern struct omap_vdd_dep_info omap446x_vddmpu_dep_info[]; +extern struct omap_vdd_dep_info omap446x_vddiva_dep_info[]; #endif /* __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H */ diff --git a/arch/arm/mach-omap2/omap_pmic.c b/arch/arm/mach-omap2/omap_pmic.c new file mode 100644 index 0000000..3271bfe --- /dev/null +++ b/arch/arm/mach-omap2/omap_pmic.c @@ -0,0 +1,105 @@ +/* + * Registration hooks for PMICs used with OMAP + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> + +#include "voltage.h" + +#include "pm.h" + +/** + * omap_pmic_data_init() - trigger point for all PMIC initializers + */ +void __init omap_pmic_data_init(void) +{ + omap_twl_init(); + omap_tps6236x_init(); +} + +/** + * omap_pmic_register_data() - Register the PMIC information to OMAP mapping + * @omap_pmic_maps: array ending with a empty element representing the maps + * @desc: description for this PMIC. + */ +int __init omap_pmic_register_data(struct omap_pmic_map *omap_pmic_maps, + struct omap_pmic_description *desc) +{ + struct voltagedomain *voltdm; + struct omap_pmic_map *map; + int r; + + if (!omap_pmic_maps) + return 0; + + map = omap_pmic_maps; + + while (map->name) { + if (!omap_chip_is(map->omap_chip)) + goto next; + + /* The base PMIC is the one controlling core voltdm */ + if (desc && !strcmp(map->name, "core")) + omap_pm_set_pmic_lp_time(desc->pmic_lp_tstart, + desc->pmic_lp_tshut); + + voltdm = voltdm_lookup(map->name); + if (IS_ERR_OR_NULL(voltdm)) { + pr_err("%s: unable to find map %s\n", __func__, + map->name); + goto next; + } + if (IS_ERR_OR_NULL(map->pmic_data)) { + pr_warning("%s: domain[%s] has no pmic data\n", + __func__, map->name); + goto next; + } + + r = omap_voltage_register_pmic(voltdm, map->pmic_data); + if (r) { + pr_warning("%s: domain[%s] register returned %d\n", + __func__, map->name, r); + goto next; + } + if (map->special_action) { + r = map->special_action(voltdm); + WARN(r, "%s: domain[%s] action returned %d\n", __func__, + map->name, r); + } +next: + map++; + } + + return 0; +} + +int __init omap_pmic_update(struct omap_pmic_map *tmp_map, char *name, + u32 old_chip_id, u32 new_chip_id) +{ + while (tmp_map->name != NULL) { + if (!strcmp(tmp_map->name, name) && + (tmp_map->omap_chip.oc & new_chip_id)) { + WARN(1, "%s: this map already exists:%s-%x\n", + __func__, name, new_chip_id); + return -1; + } + if (!strcmp(tmp_map->name, name) && + (tmp_map->omap_chip.oc & old_chip_id)) + break; + tmp_map++; + } + if (tmp_map->name != NULL) { + tmp_map->omap_chip.oc = new_chip_id; + return 0; + } + return -ENOENT; +} diff --git a/arch/arm/mach-omap2/omap_tps6236x.c b/arch/arm/mach-omap2/omap_tps6236x.c new file mode 100644 index 0000000..c369d7a --- /dev/null +++ b/arch/arm/mach-omap2/omap_tps6236x.c @@ -0,0 +1,434 @@ +/* + * OMAP and TPS6236x specific initialization + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Vishwanath BS + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/i2c/twl.h> + +#include "pm.h" +#include "vc.h" +#include "mux.h" + +/* Voltage limits supported */ +#define MIN_VOLTAGE_TPS62360_62_UV 770000 +#define MAX_VOLTAGE_TPS62360_62_UV 1400000 + +#define MIN_VOLTAGE_TPS62361_UV 500000 +#define MAX_VOLTAGE_TPS62361_UV 1770000 + +#define MAX_VOLTAGE_RAMP_TPS6236X_UV 32000 + +/* + * This is the voltage delta between 2 values in voltage register. + * when switching voltage V1 to V2, TPS62361 can ramp up or down + * initially with step sizes of 20mV with a last step of 10mV. + * In the case of TPS6236[0|2], it is a constant 10mV steps + * we choose the 10mV step for linearity when SR is configured. + */ +#define STEP_SIZE_TPS6236X 10000 + +/* I2C access parameters */ +#define I2C_TPS6236X_SLAVE_ADDR 0x60 + +#define DEF_SET_REG(VSEL0, VSEL1) (((VSEL1) << 1| (VSEL0) << 0) & 0x3) +#define REG_TPS6236X_SET_0 0x00 +#define REG_TPS6236X_SET_1 0x01 +#define REG_TPS6236X_SET_2 0x02 +#define REG_TPS6236X_SET_3 0x03 +#define REG_TPS6236X_CTRL 0x04 +#define REG_TPS6236X_TEMP 0x05 +#define REG_TPS6236X_RAMP_CTRL 0x06 +#define REG_TPS6236X_CHIP_ID0 0x08 +#define REG_TPS6236X_CHIP_ID1 0x09 + +#define MODE_TPS6236X_AUTO_PFM_PWM 0x00 +#define MODE_TPS6236X_FORCE_PWM BIT(7) + +/* We use Auto PFM/PWM mode currently seems to have the best trade off */ +#define VOLTAGE_PFM_MODE_VAL MODE_TPS6236X_AUTO_PFM_PWM + +#define REG_TPS6236X_RAMP_CTRL_RMP_MASK (0x7 << 5) +#define REG_TPS6236X_RAMP_CTRL_EN_DISC BIT(2) +#define REG_TPS6236X_RAMP_CTRL_RAMP_PFM BIT(1) + +#define REG_TPS6236X_CTRL_PD_EN BIT(7) +#define REG_TPS6236X_CTRL_PD_VSEL0 BIT(6) +#define REG_TPS6236X_CTRL_PD_VSEL1 BIT(5) + +/* TWL usage */ +#define TWL6030_REG_SYSEN_CFG_GRP 0xB3 +#define TWL6030_REG_SYSEN_CFG_TRANS 0xB4 +#define TWL6030_REG_VCORE3_CFG_GRP 0x5E +#define TWL6030_REG_VMEM_CFG_GRP 0x64 +#define TWL6030_REG_MSK_TRANSITION 0x20 +#define TWL6030_BIT_APE_GRP BIT(0) +#define TWL6030_BIT_CON_GRP BIT(1) +#define TWL6030_BIT_MOD_GRP BIT(2) +#define TWL6030_MSK_PREQ1 BIT(5) +#define TWL6030_MSK_SYSEN_OFF (0x3 << 4) +#define TWL6030_MSK_SYSEN_SLEEP (0x3 << 2) +#define TWL6030_MSK_SYSEN_ACTIVE (0x3 << 0) + +/* Voltage params of the attached device (all in uV) */ +static unsigned long voltage_min; +static unsigned long voltage_max; + +/* Which register do we use by default? */ +static int __initdata default_reg = -1;; + +/* Do we need to setup internal pullups? */ +static int __initdata pd_vsel0 = -1; +static int __initdata pd_vsel1 = -1; + +static int __init _bd_setup(char *name,int gpio_vsel, int *pull, int *pd_vsel) +{ + int pull_dir; + int r; + + if (gpio_vsel == -1) { + if (*pull != -1) { + *pd_vsel = (*pull == OMAP_PIN_OFF_OUTPUT_HIGH); + *pull = *pd_vsel; + } else { + *pull = 0; + } + return 0; + } + + /* if we have a pull gpio, with bad dir, pull low */ + if (*pull == -1 || (*pull != OMAP_PIN_OFF_OUTPUT_HIGH && + *pull != OMAP_PIN_OFF_OUTPUT_LOW)) + *pull = OMAP_PIN_OFF_OUTPUT_LOW; + + r = omap_mux_init_gpio(gpio_vsel, *pull); + if (r) { + pr_err("%s: unable to mux gpio%d=%d\n", __func__, + gpio_vsel, r); + goto out; + } + + pull_dir = (*pull == OMAP_PIN_OFF_OUTPUT_HIGH); + *pull = pull_dir; + + r = gpio_request(gpio_vsel, name); + if (r) { + pr_err("%s: unable to req gpio%d=%d\n", __func__, + gpio_vsel, r); + goto out; + } + r = gpio_direction_output(gpio_vsel, pull_dir); + if (r) { + pr_err("%s: unable to pull[%d] gpio%d=%d\n", __func__, + gpio_vsel, pull_dir, r); + gpio_free(gpio_vsel); + goto out; + } +out: + return r; +} + +/* Convert the ramp voltage to ramp value. */ +static u8 __init tps6236x_ramp_value(unsigned long uv) +{ + if (!uv) + return 0; + + if (uv > MAX_VOLTAGE_RAMP_TPS6236X_UV) { + pr_err("%s: uv%ld greater than max %d\n", __func__, + uv, MAX_VOLTAGE_RAMP_TPS6236X_UV); + uv = MAX_VOLTAGE_RAMP_TPS6236X_UV; + } + return fls(MAX_VOLTAGE_RAMP_TPS6236X_UV / uv) - 1; +} + +static unsigned long tps6236x_vsel_to_uv(const u8 vsel) +{ + return (voltage_min + + (STEP_SIZE_TPS6236X * (vsel & ~VOLTAGE_PFM_MODE_VAL))); +} + +static u8 tps6236x_uv_to_vsel(unsigned long uv) +{ + if (!uv) + return 0; + + /* Round off requests to limits */ + if (uv > voltage_max) { + pr_err("%s:Request for overvoltage[%ld] than supported[%ld]\n", + __func__, uv, voltage_max); + uv = voltage_max; + } + if (uv < voltage_min) { + pr_err("%s:Request for undervoltage[%ld] than supported[%ld]\n", + __func__, uv, voltage_min); + uv = voltage_min; + } + return DIV_ROUND_UP(uv - voltage_min, STEP_SIZE_TPS6236X) | + VOLTAGE_PFM_MODE_VAL; +} + +static struct omap_voltdm_pmic omap4_mpu_pmic = { + .slew_rate = 32000, + .step_size = STEP_SIZE_TPS6236X, + .on_volt = 1375000, + .onlp_volt = 1375000, + .ret_volt = 830000, + .off_volt = 0, + .volt_setup_time = 0, + .switch_on_time = 1000, + .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, + .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, + .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, + .vp_vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, + .vp_vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, + .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, + .i2c_slave_addr = I2C_TPS6236X_SLAVE_ADDR, + .volt_reg_addr = REG_TPS6236X_SET_0, + .cmd_reg_addr = REG_TPS6236X_SET_0, + .i2c_high_speed = true, + .i2c_scll_low = 0x28, + .i2c_scll_high = 0x2C, + .i2c_hscll_low = 0x0B, + .i2c_hscll_high = 0x00, + .vsel_to_uv = tps6236x_vsel_to_uv, + .uv_to_vsel = tps6236x_uv_to_vsel, +}; + +/* As per SLVSAU9 */ +static __initdata struct omap_pmic_description tps_pmic_desc = { + .pmic_lp_tshut = 1, /* T-OFF 1ns rounded */ + .pmic_lp_tstart = 1000, /* T-start */ +}; +/** + * _twl_i2c_rmw_u8() - Tiny helper function to do a read modify write for twl + * @mod_no: module number + * @mask: mask for the val + * @value: value to write + * @reg: register to write to + */ +static int __init _twl_i2c_rmw_u8(u8 mod_no, u8 mask, u8 value, u8 reg) +{ + int ret; + u8 val; + + ret = twl_i2c_read_u8(mod_no, &val, reg); + if (ret) + goto out; + + val &= ~mask; + val |= (value & mask); + + ret = twl_i2c_write_u8(mod_no, val, reg); +out: + return ret; +} + +/** + * omap4_twl_tps62361_enable() - Enable tps chip + * + * This function enables TPS chip by associating SYSEN signal + * to APE resource group of TWL6030. + * + * Returns 0 on sucess, error is returned if I2C read/write fails. + */ +static int __init omap4_twl_tps62361_enable(struct voltagedomain *voltdm) +{ + int ret = 0; + int ret1; + u8 val; + + /* Dont trust the bootloader. start with max, pm will set to proper */ + val = voltdm->pmic->uv_to_vsel(voltdm->pmic->vp_vddmax); + ret = omap_vc_bypass_send_i2c_msg(voltdm, voltdm->pmic->i2c_slave_addr, + default_reg, val); + + /* Setup Ramp */ + val = tps6236x_ramp_value(voltdm->pmic->slew_rate) << + __ffs(REG_TPS6236X_RAMP_CTRL_RMP_MASK); + val &= REG_TPS6236X_RAMP_CTRL_RMP_MASK; + + /* We would like to ramp the voltage asap */ + val |= REG_TPS6236X_RAMP_CTRL_RAMP_PFM; + + /* We would like to ramp down the voltage asap as well*/ + val |= REG_TPS6236X_RAMP_CTRL_EN_DISC; + + ret = omap_vc_bypass_send_i2c_msg(voltdm, voltdm->pmic->i2c_slave_addr, + REG_TPS6236X_RAMP_CTRL, val); + if (ret) + goto out; + + /* Setup the internal pulls to select if needed */ + if (pd_vsel0 != -1 || pd_vsel1 != -1) { + val = REG_TPS6236X_CTRL_PD_EN; + val |= (pd_vsel0) ? 0 : REG_TPS6236X_CTRL_PD_VSEL0; + val |= (pd_vsel1) ? 0 : REG_TPS6236X_CTRL_PD_VSEL1; + ret = omap_vc_bypass_send_i2c_msg(voltdm, + voltdm->pmic->i2c_slave_addr, + REG_TPS6236X_CTRL, val); + if (ret) + goto out; + } + + /* Enable thermal shutdown - 0 is enable :) */ + ret = omap_vc_bypass_send_i2c_msg(voltdm, + voltdm->pmic->i2c_slave_addr, + REG_TPS6236X_TEMP, 0x0); + if (ret) + goto out; + + /* if we have to work with TWL */ +#ifdef CONFIG_TWL4030_CORE + + /* unmask PREQ transition Executes ACT2SLP and SLP2ACT sleep sequence */ + ret1 = _twl_i2c_rmw_u8(TWL6030_MODULE_ID0, TWL6030_MSK_PREQ1, + 0x00, TWL6030_REG_MSK_TRANSITION); + if (ret1) { + pr_err("%s:Err:TWL6030: map APE PREQ1(%d)\n", __func__, ret1); + ret = ret1; + } + + /* Setup SYSEN to be 1 on Active and 0 for sleep and OFF states */ + ret1 = _twl_i2c_rmw_u8(TWL6030_MODULE_ID0, TWL6030_MSK_SYSEN_ACTIVE, + 0x01, TWL6030_REG_SYSEN_CFG_TRANS); + if (ret1) { + pr_err("%s:Err:TWL6030: sysen active(%d)\n", __func__, ret1); + ret = ret1; + } + ret1 = _twl_i2c_rmw_u8(TWL6030_MODULE_ID0, TWL6030_MSK_SYSEN_SLEEP, + 0x00, TWL6030_REG_SYSEN_CFG_TRANS); + if (ret1) { + pr_err("%s:Err:TWL6030: sysen sleep(%d)\n", __func__, ret1); + ret = ret1; + } + ret1 = _twl_i2c_rmw_u8(TWL6030_MODULE_ID0, TWL6030_MSK_SYSEN_OFF, + 0x00, TWL6030_REG_SYSEN_CFG_TRANS); + if (ret1) { + pr_err("%s:Err:TWL6030: sysen off(%d)\n", __func__, ret1); + ret = ret1; + } + + /* Map up SYSEN on TWL core to control TPS */ + ret1 = _twl_i2c_rmw_u8(TWL6030_MODULE_ID0, TWL6030_BIT_APE_GRP | + TWL6030_BIT_MOD_GRP | TWL6030_BIT_CON_GRP, + TWL6030_BIT_APE_GRP, TWL6030_REG_SYSEN_CFG_GRP); + if (ret1) { + pr_err("%s:Err:TWL6030: map APE SYEN(%d)\n", __func__, ret1); + ret = ret1; + } + + /* Since we dont use VCORE3, this should not be associated with APE */ + ret1 = _twl_i2c_rmw_u8(TWL6030_MODULE_ID0, TWL6030_BIT_APE_GRP, + 0x00, TWL6030_REG_VCORE3_CFG_GRP); + if (ret1) { + pr_err("%s:Err:TWL6030:unmap APE VCORE3(%d)\n", __func__, ret1); + ret = ret1; + } + + /* Since we dont use VMEM, this should not be associated with APE */ + ret1 = _twl_i2c_rmw_u8(TWL6030_MODULE_ID0, TWL6030_BIT_APE_GRP, + 0x00, TWL6030_REG_VMEM_CFG_GRP); + if (ret1) { + pr_err("%s:Err:TWL6030: unmap APE VMEM(%d)\n", __func__, ret1); + ret = ret1; + } +#endif + +out: + if (ret) + pr_err("%s: Error enabling TPS(%d)\n", __func__, ret); + + return ret; +} + +static __initdata struct omap_pmic_map omap_tps_map[] = { + { + .name = "mpu", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP446X), + .pmic_data = &omap4_mpu_pmic, + .special_action = omap4_twl_tps62361_enable, + }, + /* Terminator */ + { .name = NULL,.pmic_data = NULL}, +}; + +int __init omap_tps6236x_init(void) +{ + struct omap_pmic_map *map; + + /* Without registers, I wont proceed */ + if (default_reg == -1) + return -EINVAL; + + map = omap_tps_map; + + /* setup all the pmic's voltage addresses to the default one */ + while (map->name) { + map->pmic_data->volt_reg_addr = default_reg; + map->pmic_data->cmd_reg_addr = default_reg; + map++; + } + + return omap_pmic_register_data(omap_tps_map, &tps_pmic_desc); +} + +/** + * omap_tps6236x_board_setup() - provide the board config for TPS connect + * @use_62361: Do we use TPS62361 variant? + * @gpio_vsel0: If using GPIO to control VSEL0, provide gpio number, else -1 + * @gpio_vsel1: If using GPIO to control VSEL1, provide gpio number, else -1 + * @pull0: If using GPIO, provide mux mode OMAP_PIN_OFF_OUTPUT_[HIGH|LOW] + * else provide any internal pull required, -1 if unused. + * @pull1: If using GPIO, provide mux mode OMAP_PIN_OFF_OUTPUT_[HIGH|LOW] + * else provide any internal pull required, -1 if unused. + * + * TPS6236x variants of PMIC can be hooked in numerous combinations on to the + * board. Some platforms can choose to hardwire and save on a GPIO for other + * uses, while others may hook a single line for GPIO control and may ground + * the other line. support these configurations. + * + * WARNING: for platforms using GPIO, be careful to provide MUX setting + * considering OFF mode configuration as well. + */ +int __init omap_tps6236x_board_setup(bool use_62361, int gpio_vsel0, + int gpio_vsel1, int pull0, int pull1) +{ + int r; + + r = _bd_setup("tps6236x_vsel0", gpio_vsel0, &pull0, &pd_vsel0); + if (r) + goto out; + r = _bd_setup("tps6236x_vsel1", gpio_vsel1, &pull1, &pd_vsel1); + if (r) { + if (gpio_vsel0 != -1) + gpio_free(gpio_vsel0); + goto out; + } + + default_reg = ((pull1 & 0x1) << 1) | (pull0 & 0x1); + + if (use_62361) { + voltage_min = MIN_VOLTAGE_TPS62361_UV; + voltage_max = MAX_VOLTAGE_TPS62361_UV; + } else { + voltage_min = MIN_VOLTAGE_TPS62360_62_UV; + voltage_max = MAX_VOLTAGE_TPS62360_62_UV; + } +out: + return r; +} + +int __init omap_tps6236x_update(char *name, u32 old_chip_id, u32 new_chip_id) +{ + return omap_pmic_update(omap_tps_map, name, old_chip_id, new_chip_id); +} diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index 07d6140..2d00a0c 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -30,32 +30,31 @@ #define OMAP3_VP_VSTEPMAX_VSTEPMAX 0x04 #define OMAP3_VP_VLIMITTO_TIMEOUT_US 200 -#define OMAP3430_VP1_VLIMITTO_VDDMIN 0x14 -#define OMAP3430_VP1_VLIMITTO_VDDMAX 0x42 -#define OMAP3430_VP2_VLIMITTO_VDDMIN 0x18 -#define OMAP3430_VP2_VLIMITTO_VDDMAX 0x2c - -#define OMAP3630_VP1_VLIMITTO_VDDMIN 0x18 -#define OMAP3630_VP1_VLIMITTO_VDDMAX 0x3c -#define OMAP3630_VP2_VLIMITTO_VDDMIN 0x18 -#define OMAP3630_VP2_VLIMITTO_VDDMAX 0x30 - #define OMAP4_SRI2C_SLAVE_ADDR 0x12 #define OMAP4_VDD_MPU_SR_VOLT_REG 0x55 +#define OMAP4_VDD_MPU_SR_CMD_REG 0x56 #define OMAP4_VDD_IVA_SR_VOLT_REG 0x5B +#define OMAP4_VDD_IVA_SR_CMD_REG 0x5C #define OMAP4_VDD_CORE_SR_VOLT_REG 0x61 - -#define OMAP4_VP_CONFIG_ERROROFFSET 0x00 -#define OMAP4_VP_VSTEPMIN_VSTEPMIN 0x01 -#define OMAP4_VP_VSTEPMAX_VSTEPMAX 0x04 -#define OMAP4_VP_VLIMITTO_TIMEOUT_US 200 - -#define OMAP4_VP_MPU_VLIMITTO_VDDMIN 0xA -#define OMAP4_VP_MPU_VLIMITTO_VDDMAX 0x39 -#define OMAP4_VP_IVA_VLIMITTO_VDDMIN 0xA -#define OMAP4_VP_IVA_VLIMITTO_VDDMAX 0x2D -#define OMAP4_VP_CORE_VLIMITTO_VDDMIN 0xA -#define OMAP4_VP_CORE_VLIMITTO_VDDMAX 0x28 +#define OMAP4_VDD_CORE_SR_CMD_REG 0x62 + +#define TWL6030_REG_VCORE1_CFG_GRP 0x52 +#define TWL6030_REG_VCORE1_CFG_TRANS 0x53 +#define TWL6030_REG_VCORE2_CFG_GRP 0x58 +#define TWL6030_REG_VCORE2_CFG_TRANS 0x59 +#define TWL6030_REG_VCORE3_CFG_GRP 0x5e +#define TWL6030_REG_VCORE3_CFG_TRANS 0x5f +#define TWL6030_BIT_APE_GRP BIT(0) +/* + * Setup CFG_TRANS mode as follows: + * 0x00 (OFF) when in OFF state(bit offset 4) and in sleep (bit offset 2) + * 0x01 (PWM/PFM Auto) when in ACTive state (bit offset 0) + * Dont trust Bootloader or reset values to set them up for kernel. + */ +#define TWL6030_REG_VCOREx_CFG_TRANS_MODE (0x00 << 4 | \ + 0x00 << 2 | \ + 0x01 << 0) +#define TWL6030_REG_VCOREx_CFG_TRANS_MODE_DESC "OFF=OFF SLEEP=OFF ACT=AUTO" static bool is_offset_valid; static u8 smps_offset; @@ -69,6 +68,55 @@ static bool __initdata twl_sr_enable_autoinit; #define REG_SMPS_OFFSET 0xE0 #define SMARTREFLEX_ENABLE BIT(3) +/** + * struct twl_reg_setup_array - NULL terminated array giving configuration + * @addr: reg address to write to + * @val: value to write with + * @desc: description of this reg for error printing + * NOTE: a NULL pointer in this indicates end of array. + * + * VCORE register configurations as per need. + */ +struct twl_reg_setup_array { + u8 addr; + u8 val; + char *desc; +}; + +/** + * _twl_set_regs() - helper to setup a config array + * @gendesc: generic description - used with error message + * @sarray: NULL terminated array of configuration values + * + * Configures TWL with a set of values terminated. If any write fails, + * this continues till the last and returns back with the last error + * value. + */ +static int __init _twl_set_regs(char *gendesc, + struct twl_reg_setup_array *sarray) +{ + int i = 0; + int ret1; + int ret = 0; + + while (sarray->desc) { + ret1 = twl_i2c_write_u8(TWL6030_MODULE_ID0, + sarray->val, + sarray->addr); + if (ret1) { + pr_err("%s: %s: failed(%d), array index=%d, desc=%s, " + "reg=0x%02x, val=0x%02x\n", + __func__, gendesc, ret1, i, + sarray->desc, sarray->addr, sarray->val); + ret = ret1; + } + sarray++; + i++; + } + + return ret; +} + static unsigned long twl4030_vsel_to_uv(const u8 vsel) { return (((vsel * 125) + 6000)) * 100; @@ -95,6 +143,8 @@ static unsigned long twl6030_vsel_to_uv(const u8 vsel) is_offset_valid = true; } + if (!vsel) + return 0; /* * There is no specific formula for voltage to vsel * conversion above 1.3V. There are special hardcoded @@ -106,9 +156,9 @@ static unsigned long twl6030_vsel_to_uv(const u8 vsel) return 1350000; if (smps_offset & 0x8) - return ((((vsel - 1) * 125) + 7000)) * 100; + return ((((vsel - 1) * 1266) + 70900)) * 10; else - return ((((vsel - 1) * 125) + 6000)) * 100; + return ((((vsel - 1) * 1266) + 60770)) * 10; } static u8 twl6030_uv_to_vsel(unsigned long uv) @@ -127,6 +177,8 @@ static u8 twl6030_uv_to_vsel(unsigned long uv) is_offset_valid = true; } + if (!uv) + return 0x00; /* * There is no specific formula for voltage to vsel * conversion above 1.3V. There are special hardcoded @@ -134,16 +186,21 @@ static u8 twl6030_uv_to_vsel(unsigned long uv) * hardcoding only for 1.35 V which is used for 1GH OPP for * OMAP4430. */ - if (uv == 1350000) + if (uv > twl6030_vsel_to_uv(0x39)) { + if (uv == 1350000) + return 0x3A; + pr_err("%s:OUT OF RANGE! non mapped vsel for %ld Vs max %ld\n", + __func__, uv, twl6030_vsel_to_uv(0x39)); return 0x3A; + } if (smps_offset & 0x8) - return DIV_ROUND_UP(uv - 700000, 12500) + 1; + return DIV_ROUND_UP(uv - 709000, 12660) + 1; else - return DIV_ROUND_UP(uv - 600000, 12500) + 1; + return DIV_ROUND_UP(uv - 607700, 12660) + 1; } -static struct omap_volt_pmic_info omap3_mpu_volt_info = { +static struct omap_voltdm_pmic omap3_mpu_pmic = { .slew_rate = 4000, .step_size = 12500, .on_volt = 1200000, @@ -158,12 +215,13 @@ static struct omap_volt_pmic_info omap3_mpu_volt_info = { .vp_vddmax = OMAP3430_VP1_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, - .pmic_reg = OMAP3_VDD_MPU_SR_CONTROL_REG, + .volt_reg_addr = OMAP3_VDD_MPU_SR_CONTROL_REG, + .i2c_high_speed = true, .vsel_to_uv = twl4030_vsel_to_uv, .uv_to_vsel = twl4030_uv_to_vsel, }; -static struct omap_volt_pmic_info omap3_core_volt_info = { +static struct omap_voltdm_pmic omap3_core_pmic = { .slew_rate = 4000, .step_size = 12500, .on_volt = 1200000, @@ -178,19 +236,21 @@ static struct omap_volt_pmic_info omap3_core_volt_info = { .vp_vddmax = OMAP3430_VP2_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, - .pmic_reg = OMAP3_VDD_CORE_SR_CONTROL_REG, + .volt_reg_addr = OMAP3_VDD_CORE_SR_CONTROL_REG, + .i2c_high_speed = true, .vsel_to_uv = twl4030_vsel_to_uv, .uv_to_vsel = twl4030_uv_to_vsel, }; -static struct omap_volt_pmic_info omap4_mpu_volt_info = { - .slew_rate = 4000, - .step_size = 12500, - .on_volt = 1350000, - .onlp_volt = 1350000, - .ret_volt = 837500, - .off_volt = 600000, +static struct omap_voltdm_pmic omap443x_mpu_pmic = { + .slew_rate = 9000, + .step_size = 12660, + .on_volt = 1375000, + .onlp_volt = 1375000, + .ret_volt = 830000, + .off_volt = 0, .volt_setup_time = 0, + .switch_on_time = 549, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, @@ -198,19 +258,26 @@ static struct omap_volt_pmic_info omap4_mpu_volt_info = { .vp_vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, - .pmic_reg = OMAP4_VDD_MPU_SR_VOLT_REG, + .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG, + .cmd_reg_addr = OMAP4_VDD_MPU_SR_CMD_REG, + .i2c_high_speed = true, + .i2c_scll_low = 0x28, + .i2c_scll_high = 0x2C, + .i2c_hscll_low = 0x0B, + .i2c_hscll_high = 0x00, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, }; -static struct omap_volt_pmic_info omap4_iva_volt_info = { - .slew_rate = 4000, - .step_size = 12500, - .on_volt = 1100000, - .onlp_volt = 1100000, - .ret_volt = 837500, - .off_volt = 600000, +static struct omap_voltdm_pmic omap4_iva_pmic = { + .slew_rate = 9000, + .step_size = 12660, + .on_volt = 1188000, + .onlp_volt = 1188000, + .ret_volt = 830000, + .off_volt = 0, .volt_setup_time = 0, + .switch_on_time = 549, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, @@ -218,19 +285,26 @@ static struct omap_volt_pmic_info omap4_iva_volt_info = { .vp_vddmax = OMAP4_VP_IVA_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, - .pmic_reg = OMAP4_VDD_IVA_SR_VOLT_REG, + .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG, + .cmd_reg_addr = OMAP4_VDD_IVA_SR_CMD_REG, + .i2c_high_speed = true, + .i2c_scll_low = 0x28, + .i2c_scll_high = 0x2C, + .i2c_hscll_low = 0x0B, + .i2c_hscll_high = 0x00, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, }; -static struct omap_volt_pmic_info omap4_core_volt_info = { - .slew_rate = 4000, - .step_size = 12500, - .on_volt = 1100000, - .onlp_volt = 1100000, - .ret_volt = 837500, - .off_volt = 600000, +static struct omap_voltdm_pmic omap443x_core_pmic = { + .slew_rate = 9000, + .step_size = 12660, + .on_volt = 1200000, + .onlp_volt = 1200000, + .ret_volt = 830000, + .off_volt = 0, .volt_setup_time = 0, + .switch_on_time = 549, .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, @@ -238,43 +312,49 @@ static struct omap_volt_pmic_info omap4_core_volt_info = { .vp_vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, - .pmic_reg = OMAP4_VDD_CORE_SR_VOLT_REG, + .i2c_high_speed = true, + .i2c_scll_low = 0x28, + .i2c_scll_high = 0x2C, + .i2c_hscll_low = 0x0B, + .i2c_hscll_high = 0x00, + .volt_reg_addr = OMAP4_VDD_CORE_SR_VOLT_REG, + .cmd_reg_addr = OMAP4_VDD_CORE_SR_CMD_REG, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, }; -int __init omap4_twl_init(void) -{ - struct voltagedomain *voltdm; - - if (!cpu_is_omap44xx()) - return -ENODEV; - - voltdm = omap_voltage_domain_lookup("mpu"); - omap_voltage_register_pmic(voltdm, &omap4_mpu_volt_info); - - voltdm = omap_voltage_domain_lookup("iva"); - omap_voltage_register_pmic(voltdm, &omap4_iva_volt_info); - - voltdm = omap_voltage_domain_lookup("core"); - omap_voltage_register_pmic(voltdm, &omap4_core_volt_info); - - return 0; -} +/* Core uses the MPU rail of 4430 */ +static struct omap_voltdm_pmic omap446x_core_pmic = { + .slew_rate = 9000, + .step_size = 12660, + .on_volt = 1200000, + .onlp_volt = 1200000, + .ret_volt = 830000, + /* OMAP4 + TWL + TPS limitation keep off_volt same as ret_volt */ + .off_volt = 830000, + .volt_setup_time = 0, + .switch_on_time = 549, + .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, + .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, + .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, + .vp_vddmin = OMAP4_VP_CORE_VLIMITTO_VDDMIN, + .vp_vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, + .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, + .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, + .i2c_high_speed = true, + .i2c_scll_low = 0x28, + .i2c_scll_high = 0x2C, + .i2c_hscll_low = 0x0B, + .i2c_hscll_high = 0x00, + .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG, + .cmd_reg_addr = OMAP4_VDD_MPU_SR_CMD_REG, + .vsel_to_uv = twl6030_vsel_to_uv, + .uv_to_vsel = twl6030_uv_to_vsel, +}; -int __init omap3_twl_init(void) +static int __init twl_set_sr(struct voltagedomain *voltdm) { - struct voltagedomain *voltdm; - - if (!cpu_is_omap34xx()) - return -ENODEV; - - if (cpu_is_omap3630()) { - omap3_mpu_volt_info.vp_vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN; - omap3_mpu_volt_info.vp_vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX; - omap3_core_volt_info.vp_vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN; - omap3_core_volt_info.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; - } + int r = 0; /* * The smartreflex bit on twl4030 specifies if the setting of voltage @@ -286,15 +366,144 @@ int __init omap3_twl_init(void) * voltage scaling will not function on TWL over I2C_SR. */ if (!twl_sr_enable_autoinit) - omap3_twl_set_sr_bit(true); + r = omap3_twl_set_sr_bit(true); + return r; +} + + +/* OMAP4430 - All vcores: 1, 2 and 3 should go down with PREQ */ +static __initdata struct twl_reg_setup_array omap4430_twl6030_setup[] = { + { + .addr = TWL6030_REG_VCORE1_CFG_GRP, + .val = TWL6030_BIT_APE_GRP, + .desc = "Pull VCORE1 down along with App processor's PREQ1", + }, + { + .addr = TWL6030_REG_VCORE1_CFG_TRANS, + .val = TWL6030_REG_VCOREx_CFG_TRANS_MODE, + .desc = "VCORE1" TWL6030_REG_VCOREx_CFG_TRANS_MODE_DESC, + }, + { + .addr = TWL6030_REG_VCORE2_CFG_GRP, + .val = TWL6030_BIT_APE_GRP, + .desc = "Pull VCORE2 down along with App processor's PREQ1", + }, + { + .addr = TWL6030_REG_VCORE2_CFG_TRANS, + .val = TWL6030_REG_VCOREx_CFG_TRANS_MODE, + .desc = "VCORE2" TWL6030_REG_VCOREx_CFG_TRANS_MODE_DESC, + }, + { + .addr = TWL6030_REG_VCORE3_CFG_GRP, + .val = TWL6030_BIT_APE_GRP, + .desc = "Pull VCORE3 down along with App processor's PREQ1", + }, + { + .addr = TWL6030_REG_VCORE3_CFG_TRANS, + .val = TWL6030_REG_VCOREx_CFG_TRANS_MODE, + .desc = "VCORE3" TWL6030_REG_VCOREx_CFG_TRANS_MODE_DESC, + }, + { .desc = NULL} /* TERMINATOR */ +}; - voltdm = omap_voltage_domain_lookup("mpu"); - omap_voltage_register_pmic(voltdm, &omap3_mpu_volt_info); +static int __init twl_set_4430vcore(struct voltagedomain *voltdm) +{ + return _twl_set_regs("OMAP4430 ", omap4430_twl6030_setup); +} - voltdm = omap_voltage_domain_lookup("core"); - omap_voltage_register_pmic(voltdm, &omap3_core_volt_info); +/* OMAP4460 - VCORE3 is unused, 1 and 2 should go down with PREQ */ +static __initdata struct twl_reg_setup_array omap4460_twl6030_setup[] = { + { + .addr = TWL6030_REG_VCORE1_CFG_GRP, + .val = TWL6030_BIT_APE_GRP, + .desc = "Pull VCORE1 down along with App processor's PREQ1", + }, + { + .addr = TWL6030_REG_VCORE1_CFG_TRANS, + .val = TWL6030_REG_VCOREx_CFG_TRANS_MODE, + .desc = "VCORE1" TWL6030_REG_VCOREx_CFG_TRANS_MODE_DESC, + }, + { + .addr = TWL6030_REG_VCORE2_CFG_GRP, + .val = TWL6030_BIT_APE_GRP, + .desc = "Pull VCORE2 down along with App processor's PREQ1", + }, + { + .addr = TWL6030_REG_VCORE2_CFG_TRANS, + .val = TWL6030_REG_VCOREx_CFG_TRANS_MODE, + .desc = "VCORE2" TWL6030_REG_VCOREx_CFG_TRANS_MODE_DESC, + }, + { .desc = NULL} /* TERMINATOR */ +}; - return 0; +static int __init twl_set_4460vcore(struct voltagedomain *voltdm) +{ + return _twl_set_regs("OMAP4460 ", omap4460_twl6030_setup); +} + +#define OMAP3_TWL4030_USED (CHIP_GE_OMAP3430ES2 | \ + CHIP_GE_OMAP3630ES1_1 | \ + CHIP_IS_OMAP3630ES1) + +static __initdata struct omap_pmic_map omap_twl_map[] = { + { + .name = "mpu_iva", + .omap_chip = OMAP_CHIP_INIT(OMAP3_TWL4030_USED), + .pmic_data = &omap3_mpu_pmic, + .special_action = twl_set_sr, + }, + { + .name = "core", + .omap_chip = OMAP_CHIP_INIT(OMAP3_TWL4030_USED), + .pmic_data = &omap3_core_pmic, + }, + { + .name = "mpu", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP443X), + .pmic_data = &omap443x_mpu_pmic, + }, + { + .name = "core", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP443X), + .pmic_data = &omap443x_core_pmic, + .special_action = twl_set_4430vcore, + }, + { + .name = "core", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP446X), + .pmic_data = &omap446x_core_pmic, + .special_action = twl_set_4460vcore, + }, + { + .name = "iva", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pmic_data = &omap4_iva_pmic, + }, + /* Terminator */ + { .name = NULL, .pmic_data = NULL}, +}; + +/* As per SWCS045 */ +static __initdata struct omap_pmic_description twl6030_pmic_desc = { + .pmic_lp_tshut = 500, /* T-OFF */ + .pmic_lp_tstart = 500, /* T-ON */ +}; + +int __init omap_twl_init(void) +{ + struct omap_pmic_description *desc = NULL; + + /* Reuse OMAP3430 values */ + if (cpu_is_omap3630()) { + omap3_mpu_pmic.vp_vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN; + omap3_mpu_pmic.vp_vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX; + omap3_core_pmic.vp_vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN; + omap3_core_pmic.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; + } + if (cpu_is_omap44xx()) + desc = &twl6030_pmic_desc; + + return omap_pmic_register_data(omap_twl_map, desc); } /** @@ -337,3 +546,8 @@ err: pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret); return ret; } + +int __init omap_twl_pmic_update(char *name, u32 old_chip_id, u32 new_chip_id) +{ + return omap_pmic_update(omap_twl_map, name, old_chip_id, new_chip_id); +} diff --git a/arch/arm/mach-omap2/opp.c b/arch/arm/mach-omap2/opp.c index 0627494..1858712 100644 --- a/arch/arm/mach-omap2/opp.c +++ b/arch/arm/mach-omap2/opp.c @@ -18,10 +18,13 @@ */ #include <linux/module.h> #include <linux/opp.h> +#include <linux/clk.h> #include <plat/omap_device.h> +#include <plat/clock.h> #include "omap_opp_data.h" +#include "dvfs.h" /* Temp variable to allow multiple calls */ static u8 __initdata omap_table_init; @@ -38,6 +41,8 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def, u32 opp_def_size) { int i, r; + struct clk *clk; + long round_rate; if (!opp_def || !opp_def_size) { pr_err("%s: invalid params!\n", __func__); @@ -58,19 +63,34 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def, struct device *dev; if (!opp_def->hwmod_name) { - pr_err("%s: NULL name of omap_hwmod, failing [%d].\n", - __func__, i); - return -EINVAL; + WARN(1, "%s: NULL name of omap_hwmod, failing" + " [%d].\n", __func__, i); + continue; } oh = omap_hwmod_lookup(opp_def->hwmod_name); if (!oh || !oh->od) { - pr_warn("%s: no hwmod or odev for %s, [%d] " + WARN(1, "%s: no hwmod or odev for %s, [%d] " "cannot add OPPs.\n", __func__, opp_def->hwmod_name, i); - return -EINVAL; + continue; } dev = &oh->od->pdev.dev; + clk = omap_clk_get_by_name(opp_def->clk_name); + if (clk) { + round_rate = clk_round_rate(clk, opp_def->freq); + if (round_rate > 0) { + opp_def->freq = round_rate; + } else { + WARN(1, "%s: round_rate for clock %s failed\n", + __func__, opp_def->clk_name); + continue; /* skip Bad OPP */ + } + } else { + WARN(1, "%s: No clock by name %s found\n", __func__, + opp_def->clk_name); + continue; /* skip Bad OPP */ + } r = opp_add(dev, opp_def->freq, opp_def->u_volt); if (r) { dev_err(dev, "%s: add OPP %ld failed for %s [%d] " @@ -85,6 +105,12 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def, "[%d] result=%d\n", __func__, opp_def->freq, opp_def->hwmod_name, i, r); + + r = omap_dvfs_register_device(dev, + opp_def->voltdm_name, opp_def->clk_name); + if (r) + dev_err(dev, "%s:%s:err dvfs register %d %d\n", + __func__, opp_def->hwmod_name, r, i); } } diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c index d95f3f9..41619ea 100644 --- a/arch/arm/mach-omap2/opp3xxx_data.c +++ b/arch/arm/mach-omap2/opp3xxx_data.c @@ -36,12 +36,12 @@ #define OMAP3430_VDD_MPU_OPP5_UV 1350000 struct omap_volt_data omap34xx_vddmpu_volt_data[] = { - VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD1, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD1, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD1, 0xf9, 0x18), - VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP4_UV, OMAP343X_CONTROL_FUSE_OPP4_VDD1, 0xf9, 0x18), - VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP5_UV, OMAP343X_CONTROL_FUSE_OPP5_VDD1, 0xf9, 0x18), - VOLT_DATA_DEFINE(0, 0, 0, 0), + VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP1_UV, 0, OMAP343X_CONTROL_FUSE_OPP1_VDD1, 0xf4, 0x0c, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP2_UV, 0, OMAP343X_CONTROL_FUSE_OPP2_VDD1, 0xf4, 0x0c, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV, 0, OMAP343X_CONTROL_FUSE_OPP3_VDD1, 0xf9, 0x18, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP4_UV, 0, OMAP343X_CONTROL_FUSE_OPP4_VDD1, 0xf9, 0x18, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP5_UV, 0, OMAP343X_CONTROL_FUSE_OPP5_VDD1, 0xf9, 0x18, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), }; /* VDD2 */ @@ -51,10 +51,28 @@ struct omap_volt_data omap34xx_vddmpu_volt_data[] = { #define OMAP3430_VDD_CORE_OPP3_UV 1150000 struct omap_volt_data omap34xx_vddcore_volt_data[] = { - VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD2, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD2, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD2, 0xf9, 0x18), - VOLT_DATA_DEFINE(0, 0, 0, 0), + VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP1_UV, 0, OMAP343X_CONTROL_FUSE_OPP1_VDD2, 0xf4, 0x0c, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP2_UV, 0, OMAP343X_CONTROL_FUSE_OPP2_VDD2, 0xf4, 0x0c, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP3_UV, 0, OMAP343X_CONTROL_FUSE_OPP3_VDD2, 0xf9, 0x18, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), +}; + +/* OMAP 3430 MPU Core VDD dependency table */ +static struct omap_vdd_dep_volt omap34xx_vdd_mpu_core_dep_data[] = { + {.main_vdd_volt = OMAP3430_VDD_MPU_OPP1_UV, .dep_vdd_volt = OMAP3430_VDD_CORE_OPP2_UV}, + {.main_vdd_volt = OMAP3430_VDD_MPU_OPP2_UV, .dep_vdd_volt = OMAP3430_VDD_CORE_OPP2_UV}, + {.main_vdd_volt = OMAP3430_VDD_MPU_OPP3_UV, .dep_vdd_volt = OMAP3430_VDD_CORE_OPP3_UV}, + {.main_vdd_volt = OMAP3430_VDD_MPU_OPP4_UV, .dep_vdd_volt = OMAP3430_VDD_CORE_OPP3_UV}, + {.main_vdd_volt = OMAP3430_VDD_MPU_OPP5_UV, .dep_vdd_volt = OMAP3430_VDD_CORE_OPP3_UV}, +}; + +struct omap_vdd_dep_info omap34xx_vddmpu_dep_info[] = { + { + .name = "core", + .dep_table = omap34xx_vdd_mpu_core_dep_data, + .nr_dep_entries = ARRAY_SIZE(omap34xx_vdd_mpu_core_dep_data), + }, + {.name = NULL, .dep_table = NULL, .nr_dep_entries = 0}, }; /* 36xx */ @@ -67,11 +85,11 @@ struct omap_volt_data omap34xx_vddcore_volt_data[] = { #define OMAP3630_VDD_MPU_OPP1G_UV 1375000 struct omap_volt_data omap36xx_vddmpu_volt_data[] = { - VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD1, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD1, 0xf9, 0x16), - VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP120_UV, OMAP3630_CONTROL_FUSE_OPP120_VDD1, 0xfa, 0x23), - VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP1G_UV, OMAP3630_CONTROL_FUSE_OPP1G_VDD1, 0xfa, 0x27), - VOLT_DATA_DEFINE(0, 0, 0, 0), + VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP50_UV, 0, OMAP3630_CONTROL_FUSE_OPP50_VDD1, 0xf4, 0x0c, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP100_UV, 0, OMAP3630_CONTROL_FUSE_OPP100_VDD1, 0xf9, 0x16, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP120_UV, 0, OMAP3630_CONTROL_FUSE_OPP120_VDD1, 0xfa, 0x23, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP1G_UV, 0, OMAP3630_CONTROL_FUSE_OPP1G_VDD1, 0xfa, 0x27, OMAP_ABB_FAST_OPP), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), }; /* VDD2 */ @@ -80,24 +98,24 @@ struct omap_volt_data omap36xx_vddmpu_volt_data[] = { #define OMAP3630_VDD_CORE_OPP100_UV 1200000 struct omap_volt_data omap36xx_vddcore_volt_data[] = { - VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD2, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD2, 0xf9, 0x16), - VOLT_DATA_DEFINE(0, 0, 0, 0), + VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP50_UV, 0, OMAP3630_CONTROL_FUSE_OPP50_VDD2, 0xf4, 0x0c, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP100_UV, 0, OMAP3630_CONTROL_FUSE_OPP100_VDD2, 0xf9, 0x16, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), }; /* OPP data */ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = { /* MPU OPP1 */ - OPP_INITIALIZER("mpu", true, 125000000, OMAP3430_VDD_MPU_OPP1_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", true, 125000000, OMAP3430_VDD_MPU_OPP1_UV), /* MPU OPP2 */ - OPP_INITIALIZER("mpu", true, 250000000, OMAP3430_VDD_MPU_OPP2_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", true, 250000000, OMAP3430_VDD_MPU_OPP2_UV), /* MPU OPP3 */ - OPP_INITIALIZER("mpu", true, 500000000, OMAP3430_VDD_MPU_OPP3_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", true, 500000000, OMAP3430_VDD_MPU_OPP3_UV), /* MPU OPP4 */ - OPP_INITIALIZER("mpu", true, 550000000, OMAP3430_VDD_MPU_OPP4_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", true, 550000000, OMAP3430_VDD_MPU_OPP4_UV), /* MPU OPP5 */ - OPP_INITIALIZER("mpu", true, 600000000, OMAP3430_VDD_MPU_OPP5_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", true, 600000000, OMAP3430_VDD_MPU_OPP5_UV), /* * L3 OPP1 - 41.5 MHz is disabled because: The voltage for that OPP is @@ -107,47 +125,64 @@ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = { * impact that frequency will do to the MPU and the whole system in * general. */ - OPP_INITIALIZER("l3_main", false, 41500000, OMAP3430_VDD_CORE_OPP1_UV), + OPP_INITIALIZER("l3_main", "dpll3_ck", "core", false, 41500000, OMAP3430_VDD_CORE_OPP1_UV), /* L3 OPP2 */ - OPP_INITIALIZER("l3_main", true, 83000000, OMAP3430_VDD_CORE_OPP2_UV), + OPP_INITIALIZER("l3_main", "dpll3_ck", "core", true, 83000000, OMAP3430_VDD_CORE_OPP2_UV), /* L3 OPP3 */ - OPP_INITIALIZER("l3_main", true, 166000000, OMAP3430_VDD_CORE_OPP3_UV), + OPP_INITIALIZER("l3_main", "dpll3_ck", "core", true, 166000000, OMAP3430_VDD_CORE_OPP3_UV), /* DSP OPP1 */ - OPP_INITIALIZER("iva", true, 90000000, OMAP3430_VDD_MPU_OPP1_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", true, 90000000, OMAP3430_VDD_MPU_OPP1_UV), /* DSP OPP2 */ - OPP_INITIALIZER("iva", true, 180000000, OMAP3430_VDD_MPU_OPP2_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", true, 180000000, OMAP3430_VDD_MPU_OPP2_UV), /* DSP OPP3 */ - OPP_INITIALIZER("iva", true, 360000000, OMAP3430_VDD_MPU_OPP3_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", true, 360000000, OMAP3430_VDD_MPU_OPP3_UV), /* DSP OPP4 */ - OPP_INITIALIZER("iva", true, 400000000, OMAP3430_VDD_MPU_OPP4_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", true, 400000000, OMAP3430_VDD_MPU_OPP4_UV), /* DSP OPP5 */ - OPP_INITIALIZER("iva", true, 430000000, OMAP3430_VDD_MPU_OPP5_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", true, 430000000, OMAP3430_VDD_MPU_OPP5_UV), }; static struct omap_opp_def __initdata omap36xx_opp_def_list[] = { /* MPU OPP1 - OPP50 */ - OPP_INITIALIZER("mpu", true, 300000000, OMAP3630_VDD_MPU_OPP50_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", true, 300000000, OMAP3630_VDD_MPU_OPP50_UV), /* MPU OPP2 - OPP100 */ - OPP_INITIALIZER("mpu", true, 600000000, OMAP3630_VDD_MPU_OPP100_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", true, 600000000, OMAP3630_VDD_MPU_OPP100_UV), /* MPU OPP3 - OPP-Turbo */ - OPP_INITIALIZER("mpu", false, 800000000, OMAP3630_VDD_MPU_OPP120_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", false, 800000000, OMAP3630_VDD_MPU_OPP120_UV), /* MPU OPP4 - OPP-SB */ - OPP_INITIALIZER("mpu", false, 1000000000, OMAP3630_VDD_MPU_OPP1G_UV), + OPP_INITIALIZER("mpu", "dpll1_ck", "mpu_iva", false, 1000000000, OMAP3630_VDD_MPU_OPP1G_UV), /* L3 OPP1 - OPP50 */ - OPP_INITIALIZER("l3_main", true, 100000000, OMAP3630_VDD_CORE_OPP50_UV), + OPP_INITIALIZER("l3_main", "dpll3_ck", "core", true, 100000000, OMAP3630_VDD_CORE_OPP50_UV), /* L3 OPP2 - OPP100, OPP-Turbo, OPP-SB */ - OPP_INITIALIZER("l3_main", true, 200000000, OMAP3630_VDD_CORE_OPP100_UV), + OPP_INITIALIZER("l3_main", "dpll3_ck", "core", true, 200000000, OMAP3630_VDD_CORE_OPP100_UV), /* DSP OPP1 - OPP50 */ - OPP_INITIALIZER("iva", true, 260000000, OMAP3630_VDD_MPU_OPP50_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", true, 260000000, OMAP3630_VDD_MPU_OPP50_UV), /* DSP OPP2 - OPP100 */ - OPP_INITIALIZER("iva", true, 520000000, OMAP3630_VDD_MPU_OPP100_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", true, 520000000, OMAP3630_VDD_MPU_OPP100_UV), /* DSP OPP3 - OPP-Turbo */ - OPP_INITIALIZER("iva", false, 660000000, OMAP3630_VDD_MPU_OPP120_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", false, 660000000, OMAP3630_VDD_MPU_OPP120_UV), /* DSP OPP4 - OPP-SB */ - OPP_INITIALIZER("iva", false, 800000000, OMAP3630_VDD_MPU_OPP1G_UV), + OPP_INITIALIZER("iva", "dpll2_ck", "mpu_iva", false, 800000000, OMAP3630_VDD_MPU_OPP1G_UV), +}; + +/* OMAP 3630 MPU Core VDD dependency table */ +static struct omap_vdd_dep_volt omap36xx_vdd_mpu_core_dep_data[] = { + {.main_vdd_volt = OMAP3630_VDD_MPU_OPP50_UV, .dep_vdd_volt = OMAP3630_VDD_CORE_OPP50_UV}, + {.main_vdd_volt = OMAP3630_VDD_MPU_OPP100_UV, .dep_vdd_volt = OMAP3630_VDD_CORE_OPP100_UV}, + {.main_vdd_volt = OMAP3630_VDD_MPU_OPP120_UV, .dep_vdd_volt = OMAP3630_VDD_CORE_OPP100_UV}, + {.main_vdd_volt = OMAP3630_VDD_MPU_OPP1G_UV, .dep_vdd_volt = OMAP3630_VDD_CORE_OPP100_UV}, +}; + +struct omap_vdd_dep_info omap36xx_vddmpu_dep_info[] = { + { + .name = "core", + .dep_table = omap36xx_vdd_mpu_core_dep_data, + .nr_dep_entries = ARRAY_SIZE(omap36xx_vdd_mpu_core_dep_data), + }, + {.name = NULL, .dep_table = NULL, .nr_dep_entries = 0}, }; /** diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c index 2293ba2..e36ca46 100644 --- a/arch/arm/mach-omap2/opp4xxx_data.c +++ b/arch/arm/mach-omap2/opp4xxx_data.c @@ -1,7 +1,7 @@ /* * OMAP4 OPP table definitions. * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ * Nishanth Menon * Kevin Hilman * Thara Gopinath @@ -19,8 +19,10 @@ * GNU General Public License for more details. */ #include <linux/module.h> +#include <linux/opp.h> #include <plat/cpu.h> +#include <plat/common.h> #include "control.h" #include "omap_opp_data.h" @@ -33,60 +35,276 @@ #define OMAP4430_VDD_MPU_OPP50_UV 1025000 #define OMAP4430_VDD_MPU_OPP100_UV 1200000 -#define OMAP4430_VDD_MPU_OPPTURBO_UV 1313000 -#define OMAP4430_VDD_MPU_OPPNITRO_UV 1375000 +#define OMAP4430_VDD_MPU_OPPTURBO_UV 1325000 +#define OMAP4430_VDD_MPU_OPPNITRO_UV 1388000 -struct omap_volt_data omap44xx_vdd_mpu_volt_data[] = { - VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP50_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP50, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP100_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP100, 0xf9, 0x16), - VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO, 0xfa, 0x23), - VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPNITRO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO, 0xfa, 0x27), - VOLT_DATA_DEFINE(0, 0, 0, 0), +struct omap_volt_data omap443x_vdd_mpu_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP50_UV, 0, OMAP44XX_CONTROL_FUSE_MPU_OPP50, 0xf4, 0x0c, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP100_UV, 0, OMAP44XX_CONTROL_FUSE_MPU_OPP100, 0xf9, 0x16, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPTURBO_UV, 0, OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO, 0xfa, 0x23, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPNITRO_UV, 0, OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO, 0xfa, 0x27, OMAP_ABB_FAST_OPP), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), }; -#define OMAP4430_VDD_IVA_OPP50_UV 1013000 -#define OMAP4430_VDD_IVA_OPP100_UV 1188000 -#define OMAP4430_VDD_IVA_OPPTURBO_UV 1300000 +#define OMAP4430_VDD_IVA_OPP50_UV 950000 +#define OMAP4430_VDD_IVA_OPP100_UV 1114000 +#define OMAP4430_VDD_IVA_OPPTURBO_UV 1291000 -struct omap_volt_data omap44xx_vdd_iva_volt_data[] = { - VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP50_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP50, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP100_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP100, 0xf9, 0x16), - VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_IVA_OPPTURBO, 0xfa, 0x23), - VOLT_DATA_DEFINE(0, 0, 0, 0), +struct omap_volt_data omap443x_vdd_iva_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP50_UV, 0, OMAP44XX_CONTROL_FUSE_IVA_OPP50, 0xf4, 0x0c, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP100_UV, 0, OMAP44XX_CONTROL_FUSE_IVA_OPP100, 0xf9, 0x16, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPPTURBO_UV, 0, OMAP44XX_CONTROL_FUSE_IVA_OPPTURBO, 0xfa, 0x23, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), }; -#define OMAP4430_VDD_CORE_OPP50_UV 1025000 -#define OMAP4430_VDD_CORE_OPP100_UV 1200000 +#define OMAP4430_VDD_CORE_OPP50_UV 962000 +#define OMAP4430_VDD_CORE_OPP100_UV 1127000 -struct omap_volt_data omap44xx_vdd_core_volt_data[] = { - VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP50_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP50, 0xf4, 0x0c), - VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP100_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP100, 0xf9, 0x16), - VOLT_DATA_DEFINE(0, 0, 0, 0), +struct omap_volt_data omap443x_vdd_core_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP50_UV, 0, OMAP44XX_CONTROL_FUSE_CORE_OPP50, 0xf4, 0x0c, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP100_UV, 0, OMAP44XX_CONTROL_FUSE_CORE_OPP100, 0xf9, 0x16, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), }; +/* Dependency of domains are as follows for OMAP4430 (OPP based): + * + * MPU IVA CORE + * 50 50 50+ + * 50 100+ 100 + * 100+ 50 100 + * 100+ 100+ 100 + */ + +/* OMAP 4430 MPU Core VDD dependency table */ +static struct omap_vdd_dep_volt omap443x_vdd_mpu_core_dep_data[] = { + {.main_vdd_volt = OMAP4430_VDD_MPU_OPP50_UV, .dep_vdd_volt = OMAP4430_VDD_CORE_OPP50_UV}, + {.main_vdd_volt = OMAP4430_VDD_MPU_OPP100_UV, .dep_vdd_volt = OMAP4430_VDD_CORE_OPP100_UV}, + {.main_vdd_volt = OMAP4430_VDD_MPU_OPPTURBO_UV, .dep_vdd_volt = OMAP4430_VDD_CORE_OPP100_UV}, + {.main_vdd_volt = OMAP4430_VDD_MPU_OPPNITRO_UV, .dep_vdd_volt = OMAP4430_VDD_CORE_OPP100_UV}, +}; + +struct omap_vdd_dep_info omap443x_vddmpu_dep_info[] = { + { + .name = "core", + .dep_table = omap443x_vdd_mpu_core_dep_data, + .nr_dep_entries = ARRAY_SIZE(omap443x_vdd_mpu_core_dep_data), + }, + {.name = NULL, .dep_table = NULL, .nr_dep_entries = 0}, +}; -static struct omap_opp_def __initdata omap44xx_opp_def_list[] = { +/* OMAP 4430 MPU IVA VDD dependency table */ +static struct omap_vdd_dep_volt omap443x_vdd_iva_core_dep_data[] = { + {.main_vdd_volt = OMAP4430_VDD_IVA_OPP50_UV, .dep_vdd_volt = OMAP4430_VDD_CORE_OPP50_UV}, + {.main_vdd_volt = OMAP4430_VDD_IVA_OPP100_UV, .dep_vdd_volt = OMAP4430_VDD_CORE_OPP100_UV}, + {.main_vdd_volt = OMAP4430_VDD_IVA_OPPTURBO_UV, .dep_vdd_volt = OMAP4430_VDD_CORE_OPP100_UV}, +}; + +struct omap_vdd_dep_info omap443x_vddiva_dep_info[] = { + { + .name = "core", + .dep_table = omap443x_vdd_iva_core_dep_data, + .nr_dep_entries = ARRAY_SIZE(omap443x_vdd_iva_core_dep_data), + }, + {.name = NULL, .dep_table = NULL, .nr_dep_entries = 0}, +}; + +static struct omap_opp_def __initdata omap443x_opp_def_list[] = { /* MPU OPP1 - OPP50 */ - OPP_INITIALIZER("mpu", true, 300000000, OMAP4430_VDD_MPU_OPP50_UV), + OPP_INITIALIZER("mpu", "dpll_mpu_ck", "mpu", true, 300000000, OMAP4430_VDD_MPU_OPP50_UV), /* MPU OPP2 - OPP100 */ - OPP_INITIALIZER("mpu", true, 600000000, OMAP4430_VDD_MPU_OPP100_UV), + OPP_INITIALIZER("mpu", "dpll_mpu_ck", "mpu", true, 600000000, OMAP4430_VDD_MPU_OPP100_UV), /* MPU OPP3 - OPP-Turbo */ - OPP_INITIALIZER("mpu", true, 800000000, OMAP4430_VDD_MPU_OPPTURBO_UV), + OPP_INITIALIZER("mpu", "dpll_mpu_ck", "mpu", true, 800000000, OMAP4430_VDD_MPU_OPPTURBO_UV), /* MPU OPP4 - OPP-SB */ - OPP_INITIALIZER("mpu", true, 1008000000, OMAP4430_VDD_MPU_OPPNITRO_UV), + OPP_INITIALIZER("mpu", "dpll_mpu_ck", "mpu", true, 1008000000, OMAP4430_VDD_MPU_OPPNITRO_UV), /* L3 OPP1 - OPP50 */ - OPP_INITIALIZER("l3_main_1", true, 100000000, OMAP4430_VDD_CORE_OPP50_UV), + OPP_INITIALIZER("l3_main_1", "virt_l3_ck", "core", true, 100000000, OMAP4430_VDD_CORE_OPP50_UV), /* L3 OPP2 - OPP100, OPP-Turbo, OPP-SB */ - OPP_INITIALIZER("l3_main_1", true, 200000000, OMAP4430_VDD_CORE_OPP100_UV), + OPP_INITIALIZER("l3_main_1", "virt_l3_ck", "core", true, 200000000, OMAP4430_VDD_CORE_OPP100_UV), /* IVA OPP1 - OPP50 */ - OPP_INITIALIZER("iva", true, 133000000, OMAP4430_VDD_IVA_OPP50_UV), + OPP_INITIALIZER("iva", "dpll_iva_m5x2_ck", "iva", true, 133000000, OMAP4430_VDD_IVA_OPP50_UV), /* IVA OPP2 - OPP100 */ - OPP_INITIALIZER("iva", true, 266100000, OMAP4430_VDD_IVA_OPP100_UV), + OPP_INITIALIZER("iva", "dpll_iva_m5x2_ck", "iva", true, 266100000, OMAP4430_VDD_IVA_OPP100_UV), /* IVA OPP3 - OPP-Turbo */ - OPP_INITIALIZER("iva", false, 332000000, OMAP4430_VDD_IVA_OPPTURBO_UV), - /* TODO: add DSP, aess, fdif, gpu */ + OPP_INITIALIZER("iva", "dpll_iva_m5x2_ck", "iva", false, 332000000, OMAP4430_VDD_IVA_OPPTURBO_UV), + /* SGX OPP1 - OPP50 */ + OPP_INITIALIZER("gpu", "dpll_per_m7x2_ck", "core", true, 153600000, OMAP4430_VDD_CORE_OPP50_UV), + /* SGX OPP2 - OPP100 */ + OPP_INITIALIZER("gpu", "dpll_per_m7x2_ck", "core", true, 307200000, OMAP4430_VDD_CORE_OPP100_UV), + /* FDIF OPP1 - OPP25 */ + OPP_INITIALIZER("fdif", "fdif_fck", "core", true, 32000000, OMAP4430_VDD_CORE_OPP50_UV), + /* FDIF OPP2 - OPP50 */ + OPP_INITIALIZER("fdif", "fdif_fck", "core", true, 64000000, OMAP4430_VDD_CORE_OPP50_UV), + /* FDIF OPP3 - OPP100 */ + OPP_INITIALIZER("fdif", "fdif_fck", "core", true, 128000000, OMAP4430_VDD_CORE_OPP100_UV), + /* DSP OPP1 - OPP50 */ + OPP_INITIALIZER("dsp", "dpll_iva_m4x2_ck", "iva", true, 232750000, OMAP4430_VDD_IVA_OPP50_UV), + /* DSP OPP2 - OPP100 */ + OPP_INITIALIZER("dsp", "dpll_iva_m4x2_ck", "iva", true, 465500000, OMAP4430_VDD_IVA_OPP100_UV), + /* DSP OPP3 - OPPTB */ + OPP_INITIALIZER("dsp", "dpll_iva_m4x2_ck", "iva", false, 496000000, OMAP4430_VDD_IVA_OPPTURBO_UV), + /* HSI OPP1 - OPP50 */ + OPP_INITIALIZER("hsi", "hsi_fck", "core", true, 96000000, OMAP4430_VDD_CORE_OPP50_UV), + /* HSI OPP2 - OPP100 */ + OPP_INITIALIZER("hsi", "hsi_fck", "core", true, 96000000, OMAP4430_VDD_CORE_OPP100_UV), + /* ABE OPP1 - OPP50 */ + OPP_INITIALIZER("aess", "abe_clk", "iva", true, 98304000, OMAP4430_VDD_IVA_OPP50_UV), + /* ABE OPP2 - OPP100 */ + OPP_INITIALIZER("aess", "abe_clk", "iva", true, 196608000, OMAP4430_VDD_IVA_OPP100_UV), +}; + +#define OMAP4460_VDD_MPU_OPP50_UV 1025000 +#define OMAP4460_VDD_MPU_OPP100_UV 1203000 +#define OMAP4460_VDD_MPU_OPPTURBO_UV 1317000 +#define OMAP4460_VDD_MPU_OPPNITRO_UV 1380000 + +struct omap_volt_data omap446x_vdd_mpu_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4460_VDD_MPU_OPP50_UV, 10000, OMAP44XX_CONTROL_FUSE_MPU_OPP50, 0xf4, 0x0c, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4460_VDD_MPU_OPP100_UV, 0, OMAP44XX_CONTROL_FUSE_MPU_OPP100, 0xf9, 0x16, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4460_VDD_MPU_OPPTURBO_UV, 0, OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO, 0xfa, 0x23, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4460_VDD_MPU_OPPNITRO_UV, 0, OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO, 0xfa, 0x27, OMAP_ABB_FAST_OPP), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), +}; + +#define OMAP4460_VDD_IVA_OPP50_UV 950000 +#define OMAP4460_VDD_IVA_OPP100_UV 1140000 +#define OMAP4460_VDD_IVA_OPPTURBO_UV 1291000 +#define OMAP4460_VDD_IVA_OPPNITRO_UV 1375000 + +struct omap_volt_data omap446x_vdd_iva_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4460_VDD_IVA_OPP50_UV, 13000, OMAP44XX_CONTROL_FUSE_IVA_OPP50, 0xf4, 0x0c, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4460_VDD_IVA_OPP100_UV, 0, OMAP44XX_CONTROL_FUSE_IVA_OPP100, 0xf9, 0x16, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4460_VDD_IVA_OPPTURBO_UV, 0, OMAP44XX_CONTROL_FUSE_IVA_OPPTURBO, 0xfa, 0x23, OMAP_ABB_NOMINAL_OPP), + VOLT_DATA_DEFINE(OMAP4460_VDD_IVA_OPPNITRO_UV, 0, OMAP44XX_CONTROL_FUSE_IVA_OPPNITRO, 0xfa, 0x23, OMAP_ABB_FAST_OPP), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), }; +#define OMAP4460_VDD_CORE_OPP50_UV 962000 +#define OMAP4460_VDD_CORE_OPP100_UV 1127000 +#define OMAP4460_VDD_CORE_OPP100_OV_UV 1250000 + +struct omap_volt_data omap446x_vdd_core_volt_data[] = { + VOLT_DATA_DEFINE(OMAP4460_VDD_CORE_OPP50_UV, 38000, OMAP44XX_CONTROL_FUSE_CORE_OPP50, 0xf4, 0x0c, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP4460_VDD_CORE_OPP100_UV, 13000, OMAP44XX_CONTROL_FUSE_CORE_OPP100, 0xf9, 0x16, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(OMAP4460_VDD_CORE_OPP100_OV_UV, 13000, OMAP44XX_CONTROL_FUSE_CORE_OPP100OV, 0xf9, 0x16, OMAP_ABB_NONE), + VOLT_DATA_DEFINE(0, 0, 0, 0, 0, 0), +}; + +/* OMAP 4460 MPU Core VDD dependency table */ +static struct omap_vdd_dep_volt omap446x_vdd_mpu_core_dep_data[] = { + {.main_vdd_volt = OMAP4460_VDD_MPU_OPP50_UV, .dep_vdd_volt = OMAP4460_VDD_CORE_OPP50_UV}, + {.main_vdd_volt = OMAP4460_VDD_MPU_OPP100_UV, .dep_vdd_volt = OMAP4460_VDD_CORE_OPP100_UV}, + {.main_vdd_volt = OMAP4460_VDD_MPU_OPPTURBO_UV, .dep_vdd_volt = OMAP4460_VDD_CORE_OPP100_UV}, + {.main_vdd_volt = OMAP4460_VDD_MPU_OPPNITRO_UV, .dep_vdd_volt = OMAP4460_VDD_CORE_OPP100_UV}, +}; + +struct omap_vdd_dep_info omap446x_vddmpu_dep_info[] = { + { + .name = "core", + .dep_table = omap446x_vdd_mpu_core_dep_data, + .nr_dep_entries = ARRAY_SIZE(omap446x_vdd_mpu_core_dep_data), + }, + {.name = NULL, .dep_table = NULL, .nr_dep_entries = 0}, +}; + +/* OMAP 4460 MPU IVA VDD dependency table */ +static struct omap_vdd_dep_volt omap446x_vdd_iva_core_dep_data[] = { + {.main_vdd_volt = OMAP4460_VDD_IVA_OPP50_UV, .dep_vdd_volt = OMAP4460_VDD_CORE_OPP50_UV}, + {.main_vdd_volt = OMAP4460_VDD_IVA_OPP100_UV, .dep_vdd_volt = OMAP4460_VDD_CORE_OPP100_UV}, + {.main_vdd_volt = OMAP4460_VDD_IVA_OPPTURBO_UV, .dep_vdd_volt = OMAP4460_VDD_CORE_OPP100_UV}, +}; + +struct omap_vdd_dep_info omap446x_vddiva_dep_info[] = { + { + .name = "core", + .dep_table = omap446x_vdd_iva_core_dep_data, + .nr_dep_entries = ARRAY_SIZE(omap446x_vdd_iva_core_dep_data), + }, + {.name = NULL, .dep_table = NULL, .nr_dep_entries = 0}, +}; + +static struct omap_opp_def __initdata omap446x_opp_def_list[] = { + /* MPU OPP1 - OPP50 */ + OPP_INITIALIZER("mpu", "virt_dpll_mpu_ck", "mpu", true, 350000000, OMAP4460_VDD_MPU_OPP50_UV), + /* MPU OPP2 - OPP100 */ + OPP_INITIALIZER("mpu", "virt_dpll_mpu_ck", "mpu", true, 700000000, OMAP4460_VDD_MPU_OPP100_UV), + /* MPU OPP3 - OPP-Turbo */ + OPP_INITIALIZER("mpu", "virt_dpll_mpu_ck", "mpu", true, 920000000, OMAP4460_VDD_MPU_OPPTURBO_UV), + /* MPU OPP4 - OPP-Nitro */ + OPP_INITIALIZER("mpu", "virt_dpll_mpu_ck", "mpu", false, 1200000000, OMAP4460_VDD_MPU_OPPNITRO_UV), + /* MPU OPP4 - OPP-Nitro SpeedBin */ + OPP_INITIALIZER("mpu", "virt_dpll_mpu_ck", "mpu", false, 1500000000, OMAP4460_VDD_MPU_OPPNITRO_UV), + /* L3 OPP1 - OPP50 */ + OPP_INITIALIZER("l3_main_1", "virt_l3_ck", "core", true, 100000000, OMAP4460_VDD_CORE_OPP50_UV), + /* L3 OPP2 - OPP100 */ + OPP_INITIALIZER("l3_main_1", "virt_l3_ck", "core", true, 200000000, OMAP4460_VDD_CORE_OPP100_UV), + OPP_INITIALIZER("l3_main_1", "virt_l3_ck", "core", true, 200000000, OMAP4460_VDD_CORE_OPP100_OV_UV), + /* IVA OPP1 - OPP50 */ + OPP_INITIALIZER("iva", "dpll_iva_m5x2_ck", "iva", true, 133000000, OMAP4460_VDD_IVA_OPP50_UV), + /* IVA OPP2 - OPP100 */ + OPP_INITIALIZER("iva", "dpll_iva_m5x2_ck", "iva", true, 266100000, OMAP4460_VDD_IVA_OPP100_UV), + /* + * IVA OPP3 - OPP-Turbo + Disabled as the reference schematics + * recommends Phoenix VCORE2 which can supply only 600mA - so the ones + * above this OPP frequency, even though OMAP is capable, should be + * enabled by board file which is sure of the chip power capability + */ + OPP_INITIALIZER("iva", "dpll_iva_m5x2_ck", "iva", false, 332000000, OMAP4460_VDD_IVA_OPPTURBO_UV), + /* IVA OPP4 - OPP-Nitro */ + OPP_INITIALIZER("iva", "dpll_iva_m5x2_ck", "iva", false, 430000000, OMAP4460_VDD_IVA_OPPNITRO_UV), + /* IVA OPP5 - OPP-Nitro SpeedBin*/ + OPP_INITIALIZER("iva", "dpll_iva_m5x2_ck", "iva", false, 500000000, OMAP4460_VDD_IVA_OPPNITRO_UV), + + /* SGX OPP1 - OPP50 */ + OPP_INITIALIZER("gpu", "dpll_per_m7x2_ck", "core", true, 153600000, OMAP4460_VDD_CORE_OPP50_UV), + /* SGX OPP2 - OPP100 */ + OPP_INITIALIZER("gpu", "dpll_per_m7x2_ck", "core", true, 307200000, OMAP4460_VDD_CORE_OPP100_UV), + /* SGX OPP3 - OPPOV */ + OPP_INITIALIZER("gpu", "dpll_per_m7x2_ck", "core", false, 384000000, OMAP4460_VDD_CORE_OPP100_OV_UV), + /* FDIF OPP1 - OPP25 */ + OPP_INITIALIZER("fdif", "fdif_fck", "core", true, 32000000, OMAP4460_VDD_CORE_OPP50_UV), + /* FDIF OPP2 - OPP50 */ + OPP_INITIALIZER("fdif", "fdif_fck", "core", true, 64000000, OMAP4460_VDD_CORE_OPP50_UV), + /* FDIF OPP3 - OPP100 */ + OPP_INITIALIZER("fdif", "fdif_fck", "core", true, 128000000, OMAP4460_VDD_CORE_OPP100_UV), + /* DSP OPP1 - OPP50 */ + OPP_INITIALIZER("dsp", "dpll_iva_m4x2_ck", "iva", true, 232750000, OMAP4460_VDD_IVA_OPP50_UV), + /* DSP OPP2 - OPP100 */ + OPP_INITIALIZER("dsp", "dpll_iva_m4x2_ck", "iva", true, 465500000, OMAP4460_VDD_IVA_OPP100_UV), + /* DSP OPP3 - OPPTB */ + OPP_INITIALIZER("dsp", "dpll_iva_m4x2_ck", "iva", false, 496000000, OMAP4460_VDD_IVA_OPPTURBO_UV), + /* HSI OPP1 - OPP50 */ + OPP_INITIALIZER("hsi", "hsi_fck", "core", true, 96000000, OMAP4460_VDD_CORE_OPP50_UV), + /* HSI OPP2 - OPP100 */ + OPP_INITIALIZER("hsi", "hsi_fck", "core", true, 96000000, OMAP4460_VDD_CORE_OPP100_UV), + /* ABE OPP1 - OPP50 */ + OPP_INITIALIZER("aess", "abe_clk", "iva", true, 98304000, OMAP4460_VDD_IVA_OPP50_UV), + /* ABE OPP2 - OPP100 */ + OPP_INITIALIZER("aess", "abe_clk", "iva", true, 196608000, OMAP4460_VDD_IVA_OPP100_UV), +}; + +/** + * omap4_mpu_opp_enable() - helper to enable the OPP + * @freq: frequency to enable + */ +static void __init omap4_mpu_opp_enable(unsigned long freq) +{ + struct device *mpu_dev; + int r; + + mpu_dev = omap2_get_mpuss_device(); + if (!mpu_dev) { + pr_err("%s: no mpu_dev, did not enable f=%ld\n", __func__, + freq); + return; + } + + r = opp_enable(mpu_dev, freq); + if (r < 0) + dev_err(mpu_dev, "%s: opp_enable failed(%d) f=%ld\n", __func__, + r, freq); +} + /** * omap4_opp_init() - initialize omap4 opp table */ @@ -96,9 +314,19 @@ int __init omap4_opp_init(void) if (!cpu_is_omap44xx()) return r; + if (cpu_is_omap443x()) + r = omap_init_opp_table(omap443x_opp_def_list, + ARRAY_SIZE(omap443x_opp_def_list)); + else if (cpu_is_omap446x()) + r = omap_init_opp_table(omap446x_opp_def_list, + ARRAY_SIZE(omap446x_opp_def_list)); - r = omap_init_opp_table(omap44xx_opp_def_list, - ARRAY_SIZE(omap44xx_opp_def_list)); + if (!r) { + if (omap4_has_mpu_1_2ghz()) + omap4_mpu_opp_enable(1200000000); + if (omap4_has_mpu_1_5ghz()) + omap4_mpu_opp_enable(1500000000); + } return r; } diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index e01da45..5942d23 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -38,11 +38,27 @@ #include "prm2xxx_3xxx.h" #include "pm.h" +#define PM_DEBUG_MAX_SAVED_REGS 64 +#define PM_DEBUG_PRM_MIN 0x4A306000 +#define PM_DEBUG_PRM_MAX (0x4A307F00 + (PM_DEBUG_MAX_SAVED_REGS * 4) - 1) +#define PM_DEBUG_CM1_MIN 0x4A004000 +#define PM_DEBUG_CM1_MAX (0x4A004F00 + (PM_DEBUG_MAX_SAVED_REGS * 4) - 1) +#define PM_DEBUG_CM2_MIN 0x4A008000 +#define PM_DEBUG_CM2_MAX (0x4A009F00 + (PM_DEBUG_MAX_SAVED_REGS * 4) - 1) + int omap2_pm_debug; u32 enable_off_mode; u32 sleep_while_idle; u32 wakeup_timer_seconds; u32 wakeup_timer_milliseconds; +u32 omap4_device_off_counter = 0; + +#ifdef CONFIG_PM_ADVANCED_DEBUG +static u32 saved_reg_num; +static u32 saved_reg_num_used; +static u32 saved_reg_addr; +static u32 saved_reg_buff[2][PM_DEBUG_MAX_SAVED_REGS]; +#endif #define DUMP_PRM_MOD_REG(mod, reg) \ regs[reg_count].name = #mod "." #reg; \ @@ -194,6 +210,8 @@ static int pm_dbg_init(void); enum { DEBUG_FILE_COUNTERS = 0, DEBUG_FILE_TIMERS, + DEBUG_FILE_LAST_COUNTERS, + DEBUG_FILE_LAST_TIMERS, }; struct pm_module_def { @@ -367,7 +385,7 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) /* Update timer for previous state */ t = sched_clock(); - pwrdm->state_timer[prev] += t - pwrdm->timer; + pwrdm->time.state[prev] += t - pwrdm->timer; pwrdm->timer = t; } @@ -389,10 +407,53 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) return 0; } +static int pwrdm_dbg_show_count_stats(struct powerdomain *pwrdm, + struct powerdomain_count_stats *stats, struct seq_file *s) +{ + int i; + + seq_printf(s, "%s (%s)", pwrdm->name, + pwrdm_state_names[pwrdm->state]); + + for (i = 0; i < PWRDM_MAX_PWRSTS; i++) + seq_printf(s, ",%s:%d", pwrdm_state_names[i], + stats->state[i]); + + seq_printf(s, ",RET-LOGIC-OFF:%d", stats->ret_logic_off); + for (i = 0; i < pwrdm->banks; i++) + seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1, + stats->ret_mem_off[i]); + + seq_printf(s, "\n"); + + return 0; +} + +static int pwrdm_dbg_show_time_stats(struct powerdomain *pwrdm, + struct powerdomain_time_stats *stats, struct seq_file *s) +{ + int i; + u64 total = 0; + + seq_printf(s, "%s (%s)", pwrdm->name, + pwrdm_state_names[pwrdm->state]); + + for (i = 0; i < 4; i++) + total += stats->state[i]; + + for (i = 0; i < 4; i++) + seq_printf(s, ",%s:%lld (%lld%%)", pwrdm_state_names[i], + stats->state[i], + total ? div64_u64(stats->state[i] * 100, total) : 0); + + seq_printf(s, "\n"); + + return 0; +} + static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) { struct seq_file *s = (struct seq_file *)user; - int i; if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || strcmp(pwrdm->name, "wkup_pwrdm") == 0 || @@ -403,25 +464,31 @@ static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n", pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm)); - seq_printf(s, "%s (%s)", pwrdm->name, - pwrdm_state_names[pwrdm->state]); - for (i = 0; i < PWRDM_MAX_PWRSTS; i++) - seq_printf(s, ",%s:%d", pwrdm_state_names[i], - pwrdm->state_counter[i]); + pwrdm_dbg_show_count_stats(pwrdm, &pwrdm->count, s); - seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter); - for (i = 0; i < pwrdm->banks; i++) - seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1, - pwrdm->ret_mem_off_counter[i]); + return 0; +} - seq_printf(s, "\n"); +static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) +{ + struct seq_file *s = (struct seq_file *)user; + + if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || + strcmp(pwrdm->name, "wkup_pwrdm") == 0 || + strncmp(pwrdm->name, "dpll", 4) == 0) + return 0; + + pwrdm_state_switch(pwrdm); + + pwrdm_dbg_show_time_stats(pwrdm, &pwrdm->time, s); return 0; } -static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) +static int pwrdm_dbg_show_last_counter(struct powerdomain *pwrdm, void *user) { struct seq_file *s = (struct seq_file *)user; + struct powerdomain_count_stats stats; int i; if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || @@ -429,22 +496,42 @@ static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) strncmp(pwrdm->name, "dpll", 4) == 0) return 0; - pwrdm_state_switch(pwrdm); + stats = pwrdm->count; + for (i = 0; i < PWRDM_MAX_PWRSTS; i++) + stats.state[i] -= pwrdm->last_count.state[i]; + for (i = 0; i < PWRDM_MAX_MEM_BANKS; i++) + stats.ret_mem_off[i] -= pwrdm->last_count.ret_mem_off[i]; + stats.ret_logic_off -= pwrdm->last_count.ret_logic_off; - seq_printf(s, "%s (%s)", pwrdm->name, - pwrdm_state_names[pwrdm->state]); + pwrdm->last_count = pwrdm->count; - for (i = 0; i < 4; i++) - seq_printf(s, ",%s:%lld", pwrdm_state_names[i], - pwrdm->state_timer[i]); + pwrdm_dbg_show_count_stats(pwrdm, &stats, s); + + return 0; +} + +static int pwrdm_dbg_show_last_timer(struct powerdomain *pwrdm, void *user) +{ + struct seq_file *s = (struct seq_file *)user; + struct powerdomain_time_stats stats; + int i; + + stats = pwrdm->time; + for (i = 0; i < PWRDM_MAX_PWRSTS; i++) + stats.state[i] -= pwrdm->last_time.state[i]; + + pwrdm->last_time = pwrdm->time; + + pwrdm_dbg_show_time_stats(pwrdm, &stats, s); - seq_printf(s, "\n"); return 0; } static int pm_dbg_show_counters(struct seq_file *s, void *unused) { pwrdm_for_each(pwrdm_dbg_show_counter, s); + if (cpu_is_omap44xx()) + seq_printf(s, "DEVICE-OFF:%d\n", omap4_device_off_counter); clkdm_for_each(clkdm_dbg_show_counter, s); return 0; @@ -456,6 +543,18 @@ static int pm_dbg_show_timers(struct seq_file *s, void *unused) return 0; } +static int pm_dbg_show_last_counters(struct seq_file *s, void *unused) +{ + pwrdm_for_each(pwrdm_dbg_show_last_counter, s); + return 0; +} + +static int pm_dbg_show_last_timers(struct seq_file *s, void *unused) +{ + pwrdm_for_each(pwrdm_dbg_show_last_timer, s); + return 0; +} + static int pm_dbg_open(struct inode *inode, struct file *file) { switch ((int)inode->i_private) { @@ -463,9 +562,15 @@ static int pm_dbg_open(struct inode *inode, struct file *file) return single_open(file, pm_dbg_show_counters, &inode->i_private); case DEBUG_FILE_TIMERS: - default: return single_open(file, pm_dbg_show_timers, &inode->i_private); + case DEBUG_FILE_LAST_COUNTERS: + return single_open(file, pm_dbg_show_last_counters, + &inode->i_private); + case DEBUG_FILE_LAST_TIMERS: + default: + return single_open(file, pm_dbg_show_last_timers, + &inode->i_private); }; } @@ -488,7 +593,7 @@ static const struct file_operations debug_reg_fops = { .release = single_release, }; -int pm_dbg_regset_init(int reg_set) +int __init pm_dbg_regset_init(int reg_set) { char name[2]; @@ -539,6 +644,47 @@ static int pwrdm_suspend_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, pwrdm_suspend_set, "%llu\n"); +#ifdef CONFIG_PM_ADVANCED_DEBUG +static bool is_addr_valid() +{ + int saved_reg_addr_max = 0; + /* Only for OMAP4 for the timebeing */ + if (!cpu_is_omap44xx()) + return false; + + saved_reg_num = (saved_reg_num > PM_DEBUG_MAX_SAVED_REGS) ? + PM_DEBUG_MAX_SAVED_REGS : saved_reg_num; + + saved_reg_addr_max = saved_reg_addr + (saved_reg_num * 4) - 1; + + if (saved_reg_addr >= PM_DEBUG_PRM_MIN && + saved_reg_addr_max <= PM_DEBUG_PRM_MAX) + return true; + if (saved_reg_addr >= PM_DEBUG_CM1_MIN && + saved_reg_addr_max <= PM_DEBUG_CM1_MAX) + return true; + if (saved_reg_addr >= PM_DEBUG_CM2_MIN && + saved_reg_addr_max <= PM_DEBUG_CM2_MAX) + return true; + return false; +} + +void omap4_pm_suspend_save_regs() +{ + int i = 0; + if (!saved_reg_num || !is_addr_valid()) + return; + + saved_reg_num_used = saved_reg_num; + + for (i = 0; i < saved_reg_num; i++) { + saved_reg_buff[1][i] = omap_readl(saved_reg_addr + (i*4)); + saved_reg_buff[0][i] = saved_reg_addr + (i*4); + } + return; +} +#endif + static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) { int i; @@ -548,7 +694,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) t = sched_clock(); for (i = 0; i < 4; i++) - pwrdm->state_timer[i] = 0; + pwrdm->time.state[i] = 0; pwrdm->timer = t; @@ -567,7 +713,19 @@ static int option_get(void *data, u64 *val) { u32 *option = data; + if (option == &enable_off_mode) { + enable_off_mode = off_mode_enabled; + } + *val = *option; +#ifdef CONFIG_PM_ADVANCED_DEBUG + if (option == &saved_reg_addr) { + int i; + for (i = 0; i < saved_reg_num_used; i++) + pr_info(" %x = %x\n", saved_reg_buff[0][i], + saved_reg_buff[1][i]); + } +#endif return 0; } @@ -579,7 +737,10 @@ static int option_set(void *data, u64 val) if (option == &wakeup_timer_milliseconds && val >= 1000) return -EINVAL; - *option = val; + if (cpu_is_omap443x() && omap_type() == OMAP2_DEVICE_TYPE_GP) + *option = 0; + else + *option = val; if (option == &enable_off_mode) { if (val) @@ -595,7 +756,7 @@ static int option_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n"); -static int pm_dbg_init(void) +static int __init pm_dbg_init(void) { int i; struct dentry *d; @@ -604,9 +765,11 @@ static int pm_dbg_init(void) if (pm_dbg_init_done) return 0; - if (cpu_is_omap34xx()) + if (cpu_is_omap34xx()) { pm_dbg_reg_modules = omap3_pm_reg_modules; - else { + } else if (cpu_is_omap44xx()) { + /* Allow pm_dbg_init on OMAP4. */ + } else { printk(KERN_ERR "%s: only OMAP3 supported\n", __func__); return -ENODEV; } @@ -619,9 +782,16 @@ static int pm_dbg_init(void) d, (void *)DEBUG_FILE_COUNTERS, &debug_fops); (void) debugfs_create_file("time", S_IRUGO, d, (void *)DEBUG_FILE_TIMERS, &debug_fops); + (void) debugfs_create_file("last_count", S_IRUGO, + d, (void *)DEBUG_FILE_LAST_COUNTERS, &debug_fops); + (void) debugfs_create_file("last_time", S_IRUGO, + d, (void *)DEBUG_FILE_LAST_TIMERS, &debug_fops); pwrdm_for_each(pwrdms_setup, (void *)d); + if (cpu_is_omap44xx()) + goto skip_reg_debufs; + pm_dbg_dir = debugfs_create_dir("registers", d); if (IS_ERR(pm_dbg_dir)) return PTR_ERR(pm_dbg_dir); @@ -637,15 +807,29 @@ static int pm_dbg_init(void) } - (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d, - &enable_off_mode, &pm_dbg_option_fops); (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUSR, d, &sleep_while_idle, &pm_dbg_option_fops); + +skip_reg_debufs: +#ifdef CONFIG_OMAP_ALLOW_OSWR + (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d, + &enable_off_mode, &pm_dbg_option_fops); +#endif (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUSR, d, &wakeup_timer_seconds, &pm_dbg_option_fops); (void) debugfs_create_file("wakeup_timer_milliseconds", S_IRUGO | S_IWUSR, d, &wakeup_timer_milliseconds, &pm_dbg_option_fops); + +#ifdef CONFIG_PM_ADVANCED_DEBUG + (void) debugfs_create_file("saved_reg_show", + S_IRUGO | S_IWUSR, d, &saved_reg_addr, + &pm_dbg_option_fops); + debugfs_create_u32("saved_reg_addr", S_IRUGO | S_IWUGO, d, + &saved_reg_addr); + debugfs_create_u32("saved_reg_num", S_IRUGO | S_IWUGO, d, + &saved_reg_num); +#endif pm_dbg_init_done = 1; return 0; diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 49486f5..4464039 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -24,30 +24,82 @@ #include "clockdomain.h" #include "pm.h" +/** + * struct omap2_pm_lp_description - Describe low power behavior of the system + * @oscillator_startup_time: Time rounded up to uSec for the oscillator to + * provide a stable clock from power on. + * @oscillator_shutdown_time: Time rounded up to uSec for oscillator to safely + * switch off. + * @pmic_startup_time: Time rounded up to uSec for the PMIC to + * provide be ready for operation from low power + * state. Note: this is not the same as voltage + * rampup time, instead, consider the PMIC to be + * in lowest power state(say OFF), this is the time + * required for it to become ready for it's DCDCs + * or LDOs to start operation. + * @pmic_shutdown_time: Time rounded up to uSec for the PMIC to + * go to low power after the LDOs are pulled to + * appropriate state. Note: this is not the same as + * voltage rampdown time, instead, consider the + * PMIC to have switched it's LDOs down, this is + * time taken to reach it's lowest power state(say + * sleep/OFF). + * + * With complex systems like OMAP, we need a generic description of system + * behavior beyond the normal description of device/peripheral operation + * which in conjunction with other parameters describe and control the low + * power operation of the device. This information tends to be specific + * to every board. + */ +struct omap2_pm_lp_description { + u32 oscillator_startup_time; + u32 oscillator_shutdown_time; + u32 pmic_startup_time; + u32 pmic_shutdown_time; +}; + +/* + * Setup time to be the max... we want to err towards the worst + * as default. rest of the system can populate these with more + * optimal values + */ +static struct omap2_pm_lp_description _pm_lp_desc = { + .oscillator_startup_time = ULONG_MAX, + .oscillator_shutdown_time = ULONG_MAX, + .pmic_startup_time = ULONG_MAX, + .pmic_shutdown_time = ULONG_MAX, +}; + static struct omap_device_pm_latency *pm_lats; static struct device *mpu_dev; static struct device *iva_dev; static struct device *l3_dev; static struct device *dsp_dev; +static struct device *fdif_dev; + +bool omap_pm_is_ready_status; struct device *omap2_get_mpuss_device(void) { WARN_ON_ONCE(!mpu_dev); return mpu_dev; } +EXPORT_SYMBOL(omap2_get_mpuss_device); struct device *omap2_get_iva_device(void) { WARN_ON_ONCE(!iva_dev); return iva_dev; } +EXPORT_SYMBOL(omap2_get_iva_device); struct device *omap2_get_l3_device(void) { WARN_ON_ONCE(!l3_dev); return l3_dev; } +EXPORT_SYMBOL(omap2_get_l3_device); struct device *omap4_get_dsp_device(void) { @@ -56,6 +108,89 @@ struct device *omap4_get_dsp_device(void) } EXPORT_SYMBOL(omap4_get_dsp_device); +struct device *omap4_get_fdif_device(void) +{ + WARN_ON_ONCE(!fdif_dev); + return fdif_dev; +} +EXPORT_SYMBOL(omap4_get_fdif_device); + +/** + * omap_pm_get_pmic_lp_time() - retrieve the oscillator time + * @tstart: pointer to startup time in uSec + * @tshut: pointer to shutdown time in uSec + * + * if the pointers are invalid, returns error, else + * populates the tstart and tshut values with the currently + * stored values. + */ +int omap_pm_get_osc_lp_time(u32 *tstart, u32 *tshut) +{ + if (!tstart || !tshut) + return -EINVAL; + + *tstart = _pm_lp_desc.oscillator_startup_time; + *tshut = _pm_lp_desc.oscillator_shutdown_time; + + return 0; +} + +/** + * omap_pm_get_pmic_lp_time() - retrieve the PMIC time + * @tstart: pointer to startup time in uSec + * @tshut: pointer to shutdown time in uSec + * + * if the pointers are invalid, returns error, else + * populates the tstart and tshut values with the currently + * stored values. + */ +int omap_pm_get_pmic_lp_time(u32 *tstart, u32 *tshut) +{ + if (!tstart || !tshut) + return -EINVAL; + + *tstart = _pm_lp_desc.pmic_startup_time; + *tshut = _pm_lp_desc.pmic_shutdown_time; + + return 0; +} + +/** + * omap_pm_set_osc_lp_time() - setup the system oscillator time + * @tstart: startup time rounded up to uSec + * @tshut: shutdown time rounded up to uSec + * + * All boards do need an oscillator for the device to function. + * The startup and stop time of these oscillators vary. Populate + * from the board file to optimize the timing. + * This function is meant to be used at boot-time configuration. + * + * NOTE: This API is intended to be invoked from board file + */ +void __init omap_pm_set_osc_lp_time(u32 tstart, u32 tshut) +{ + _pm_lp_desc.oscillator_startup_time = tstart; + _pm_lp_desc.oscillator_shutdown_time = tshut; +} + +/** + * omap_pm_set_pmic_lp_time() - setup the pmic low power time + * @tstart: startup time rounded up to uSec + * @tshut: shutdown time rounded up to uSec + * + * Store the time for PMIC to enter to lowest state supported. + * in the case of multiple PMIC on a platform, choose the one + * that ends the sequence for LP state such as OFF and starts + * the sequence such as wakeup from OFF - e.g. a PMIC that + * controls core-domain. + * This function is meant to be used at boot-time configuration. + */ +void __init omap_pm_set_pmic_lp_time(u32 tstart, u32 tshut) +{ + _pm_lp_desc.pmic_startup_time = tstart; + _pm_lp_desc.pmic_shutdown_time = tshut; +} + /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */ static int _init_omap_device(char *name, struct device **new_dev) { @@ -90,6 +225,7 @@ static void omap2_init_processor_devices(void) _init_omap_device("l3_main_1", &l3_dev); _init_omap_device("dsp", &dsp_dev); _init_omap_device("iva", &iva_dev); + _init_omap_device("fdif", &fdif_dev); } else { _init_omap_device("l3_main", &l3_dev); } @@ -106,8 +242,9 @@ static void omap2_init_processor_devices(void) int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) { u32 cur_state; - int sleep_switch = 0; + int sleep_switch = -1; int ret = 0; + int hwsup = 0; if (pwrdm == NULL || IS_ERR(pwrdm)) return -EINVAL; @@ -127,6 +264,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { sleep_switch = LOWPOWERSTATE_SWITCH; } else { + hwsup = clkdm_is_idle(pwrdm->pwrdm_clkdms[0]); clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); sleep_switch = FORCEWAKEUP_SWITCH; @@ -142,7 +280,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) switch (sleep_switch) { case FORCEWAKEUP_SWITCH: - if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO) + if (hwsup) clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); else clkdm_sleep(pwrdm->pwrdm_clkdms[0]); @@ -160,6 +298,45 @@ err: return ret; } +static int __init boot_volt_scale(struct voltagedomain *voltdm, + unsigned long boot_v) +{ + struct omap_volt_data *vdata; + int ret = 0; + + vdata = omap_voltage_get_voltdata(voltdm, boot_v); + if (IS_ERR_OR_NULL(vdata)) { + pr_err("%s:%s: Bad New voltage data for %ld\n", + __func__, voltdm->name, boot_v); + return PTR_ERR(vdata); + } + /* + * DO NOT DO abb prescale - + * case 1: OPP needs FBB, bootloader configured FBB + * - doing a prescale results in bypass -> system fail + * case 2: OPP needs FBB, bootloader does not configure FBB + * - FBB will be configured in postscale + * case 3: OPP needs bypass, bootloader configures FBB + * - bypass will be configured in postscale + * case 4: OPP needs bypass, bootloader configured in bypass + * - bypass programming in postscale skipped + */ + ret = voltdm_scale(voltdm, vdata); + if (ret) { + pr_err("%s: Fail set voltage(v=%ld)on vdd%s\n", + __func__, boot_v, voltdm->name); + return ret; + } + if (voltdm->abb) { + ret = omap_ldo_abb_post_scale(voltdm, vdata); + if (ret) { + pr_err("%s: Fail abb postscale(v=%ld)vdd%s\n", + __func__, boot_v, voltdm->name); + } + } + return ret; +} + /* * This API is to be called during init to put the various voltage * domains to the voltage as per the opp table. Typically we boot up @@ -174,14 +351,15 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, struct voltagedomain *voltdm; struct clk *clk; struct opp *opp; - unsigned long freq, bootup_volt; + unsigned long freq_cur, freq_valid, bootup_volt; + int ret = -EINVAL; if (!vdd_name || !clk_name || !dev) { printk(KERN_ERR "%s: Invalid parameters!\n", __func__); goto exit; } - voltdm = omap_voltage_domain_lookup(vdd_name); + voltdm = voltdm_lookup(vdd_name); if (IS_ERR(voltdm)) { printk(KERN_ERR "%s: Unable to get vdd pointer for vdd_%s\n", __func__, vdd_name); @@ -195,25 +373,78 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, goto exit; } - freq = clk->rate; - clk_put(clk); + freq_cur = clk->rate; + freq_valid = freq_cur; - opp = opp_find_freq_ceil(dev, &freq); + rcu_read_lock(); + opp = opp_find_freq_ceil(dev, &freq_valid); if (IS_ERR(opp)) { - printk(KERN_ERR "%s: unable to find boot up OPP for vdd_%s\n", - __func__, vdd_name); - goto exit; + opp = opp_find_freq_floor(dev, &freq_valid); + if (IS_ERR(opp)) { + rcu_read_unlock(); + pr_err("%s: no boot OPP match for %ld on vdd_%s\n", + __func__, freq_cur, vdd_name); + ret = -ENOENT; + goto exit_ck; + } } bootup_volt = opp_get_voltage(opp); + rcu_read_unlock(); if (!bootup_volt) { printk(KERN_ERR "%s: unable to find voltage corresponding" "to the bootup OPP for vdd_%s\n", __func__, vdd_name); - goto exit; + ret = -ENOENT; + goto exit_ck; } - omap_voltage_scale_vdd(voltdm, bootup_volt); - return 0; + /* + * Frequency and Voltage have to be sequenced: if we move from + * a lower frequency to higher frequency, raise voltage, followed by + * frequency, and vice versa. we assume that the voltage at boot + * is the required voltage for the frequency it was set for. + * NOTE: + * we can check the frequency, but there is numerous ways to set + * voltage. We play the safe path and just set the voltage. + */ + + if (freq_cur < freq_valid) { + ret = boot_volt_scale(voltdm, bootup_volt); + if (ret) { + pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", + __func__, vdd_name, freq_valid, + bootup_volt, vdd_name); + goto exit_ck; + } + } + + /* Set freq only if there is a difference in freq */ + if (freq_valid != freq_cur) { + ret = clk_set_rate(clk, freq_valid); + if (ret) { + pr_err("%s: Fail set clk-%s(f=%ld v=%ld)on vdd%s\n", + __func__, clk_name, freq_valid, + bootup_volt, vdd_name); + goto exit_ck; + } + } + + if (freq_cur >= freq_valid) { + ret = boot_volt_scale(voltdm, bootup_volt); + if (ret) { + pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", + __func__, clk_name, freq_valid, + bootup_volt, vdd_name); + goto exit_ck; + } + } + + ret = 0; +exit_ck: + clk_put(clk); + + if (!ret) + return 0; exit: printk(KERN_ERR "%s: Unable to put vdd_%s to its init voltage\n\n", @@ -226,7 +457,7 @@ static void __init omap3_init_voltages(void) if (!cpu_is_omap34xx()) return; - omap2_set_init_voltage("mpu", "dpll1_ck", mpu_dev); + omap2_set_init_voltage("mpu_iva", "dpll1_ck", mpu_dev); omap2_set_init_voltage("core", "l3_ick", l3_dev); } @@ -235,8 +466,12 @@ static void __init omap4_init_voltages(void) if (!cpu_is_omap44xx()) return; - omap2_set_init_voltage("mpu", "dpll_mpu_ck", mpu_dev); - omap2_set_init_voltage("core", "l3_div_ck", l3_dev); + if (cpu_is_omap446x()) { + omap2_set_init_voltage("mpu", "virt_dpll_mpu_ck", mpu_dev); + } else { + omap2_set_init_voltage("mpu", "dpll_mpu_ck", mpu_dev); + } + omap2_set_init_voltage("core", "virt_l3_ck", l3_dev); omap2_set_init_voltage("iva", "dpll_iva_m5x2_ck", iva_dev); } @@ -251,9 +486,8 @@ postcore_initcall(omap2_common_pm_init); static int __init omap2_common_pm_late_init(void) { - /* Init the OMAP TWL parameters */ - omap3_twl_init(); - omap4_twl_init(); + /* Init the OMAP PMIC parameters */ + omap_pmic_data_init(); /* Init the voltage layer */ omap_voltage_late_init(); diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 45bcfce..c9da6b9 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -17,10 +17,34 @@ extern void *omap3_secure_ram_storage; extern void omap3_pm_off_mode_enable(int); -extern void omap_sram_idle(void); +extern void omap_sram_idle(bool suspend); extern int omap3_can_sleep(void); extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state); extern int omap3_idle_init(void); +extern int omap4_idle_init(void); +extern void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, + bool suspend); +extern void omap4_trigger_ioctrl(void); +extern u32 omap4_device_off_counter; + +#ifdef CONFIG_PM +extern void omap4_device_set_state_off(u8 enable); +extern bool omap4_device_prev_state_off(void); +extern bool omap4_device_next_state_off(void); +extern void omap4_device_clear_prev_off_state(void); +#else +static inline void omap4_device_set_state_off(u8 enable) +{ +} +static inline bool omap4_device_prev_state_off(void) +{ + return false; +} +static inline bool omap4_device_next_state_off(void) +{ + return false; +} +#endif #if defined(CONFIG_PM_OPP) extern int omap3_opp_init(void); @@ -36,6 +60,15 @@ static inline int omap4_opp_init(void) } #endif +#ifdef CONFIG_PM +int omap4_pm_cold_reset(char *reason); +#else +int omap4_pm_cold_reset(char *reason) +{ + return -EINVAL; +} +#endif + /* * cpuidle mach specific parameters * @@ -68,15 +101,18 @@ extern struct omap_dm_timer *gptimer_wakeup; extern void omap2_pm_dump(int mode, int resume, unsigned int us); extern void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds); extern int omap2_pm_debug; -extern u32 enable_off_mode; extern u32 sleep_while_idle; #else #define omap2_pm_dump(mode, resume, us) do {} while (0); #define omap2_pm_wakeup_on_timer(seconds, milliseconds) do {} while (0); #define omap2_pm_debug 0 -#define enable_off_mode 0 #define sleep_while_idle 0 #endif +#ifdef CONFIG_PM_ADVANCED_DEBUG +extern void omap4_pm_suspend_save_regs(void); +#else +static inline void omap4_pm_suspend_save_regs(void) { } +#endif #if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev); @@ -125,19 +161,132 @@ static inline int omap_devinit_smartreflex(void) static inline void omap_enable_smartreflex_on_init(void) {} #endif +/** + * struct omap_pmic_map - Describe the OMAP PMIC data for OMAP + * @name: name of the voltage domain + * @pmic_data: pmic data associated with it + * @omap_chip: initialize with OMAP_CHIP_INIT the OMAP chips this data maps to + * @special_action: callback for any specific action to take for that map + * + * Since we support multiple PMICs each potentially functioning on multiple + * OMAP devices, we describe the parameters in a map allowing us to reuse the + * data as necessary. + */ +struct omap_pmic_map { + char *name; + struct omap_voltdm_pmic *pmic_data; + struct omap_chip_id omap_chip; + int (*special_action)(struct voltagedomain *); +}; + +/** + * struct omap_pmic_description - Describe low power behavior of the PMIC + * @pmic_lp_tshut: Time rounded up to uSec for the PMIC to + * go to low power after the LDOs are pulled to + * appropriate state. Note: this is not the same as + * voltage rampdown time, instead, consider the + * PMIC to have switched it's LDOs down, this is + * time taken to reach it's lowest power state(say + * sleep/OFF). + * @pmic_lp_tstart: Time rounded up to uSec for the PMIC to + * provide be ready for operation from low power + * state. Note: this is not the same as voltage + * rampup time, instead, consider the PMIC to be + * in lowest power state(say OFF), this is the time + * required for it to become ready for it's DCDCs + * or LDOs to start operation. + */ +struct omap_pmic_description { + u32 pmic_lp_tshut; + u32 pmic_lp_tstart; +}; + +#ifdef CONFIG_PM +extern int omap_pmic_register_data(struct omap_pmic_map *map, + struct omap_pmic_description *desc); +#else +static inline int omap_pmic_register_data(struct omap_pmic_map *map, + struct omap_pmic_description *desc) +{ + return -EINVAL; +} +#endif +extern void omap_pmic_data_init(void); + +extern int omap_pmic_update(struct omap_pmic_map *tmp_map, char *name, + u32 old_chip_id, u32 new_chip_id); + #ifdef CONFIG_TWL4030_CORE -extern int omap3_twl_init(void); -extern int omap4_twl_init(void); +extern int omap_twl_init(void); extern int omap3_twl_set_sr_bit(bool enable); +extern int omap_twl_pmic_update(char *name, u32 old_chip_id, u32 new_chip_id); #else -static inline int omap3_twl_init(void) +static inline int omap_twl_init(void) { return -EINVAL; } -static inline int omap4_twl_init(void) +static inline int omap_twl_pmic_update(char *name, u32 old_chip_id, + u32 new_chip_id) { return -EINVAL; } #endif +#ifdef CONFIG_OMAP_TPS6236X +extern int omap_tps6236x_board_setup(bool use_62361, int gpio_vsel0, + int gpio_vsel1, int pull0, int pull1); +extern int omap_tps6236x_init(void); + +extern int omap_tps6236x_update(char *name, u32 old_chip_id, u32 new_chip_id); +#else +static inline int omap_tps6236x_board_setup(bool use_62361, int gpio_vsel0, + int gpio_vsel1, int pull0, int pull1) +{ + return -EINVAL; +} +static inline int omap_tps6236x_init(void) +{ + return -EINVAL; +} +static inline int omap_tps6236x_update(char *name, u32 old_chip_id, + u32 new_chip_id) +{ + return -EINVAL; +} +#endif + +extern int omap4_ldo_trim_configure(void); + +#ifdef CONFIG_PM +extern bool omap_pm_is_ready_status; +/** + * omap_pm_is_ready() - tells if OMAP pm framework is done it's initialization + * + * In few cases, to sequence operations properly, we'd like to know if OMAP's PM + * framework has completed all it's expected initializations. + */ +static inline bool omap_pm_is_ready(void) +{ + return omap_pm_is_ready_status; +} +extern int omap_pm_get_osc_lp_time(u32 *tstart, u32 *tshut); +extern int omap_pm_get_pmic_lp_time(u32 *tstart, u32 *tshut); +extern void omap_pm_set_osc_lp_time(u32 tstart, u32 tshut); +extern void omap_pm_set_pmic_lp_time(u32 tstart, u32 tshut); +#else +static inline bool omap_pm_is_ready(void) +{ + return false; +} +static inline int omap_pm_get_osc_lp_time(u32 *tstart, u32 *tshut) +{ + return -EINVAL; +} +static inline int omap_pm_get_pmic_lp_time(u32 *tstart, u32 *tshut) +{ + return -EINVAL; +} +static inline void omap_pm_set_osc_lp_time(u32 tstart, u32 tshut) { } +static inline void omap_pm_set_pmic_lp_time(u32 tstart, u32 tshut) { } +#endif #endif diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index df3ded6..faa8463 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -132,26 +132,12 @@ static void omap2_enter_full_retention(void) if (omap_irq_pending()) goto no_sleep; - /* Block console output in case it is on one of the OMAP UARTs */ - if (!is_suspending()) - if (!console_trylock()) - goto no_sleep; - - omap_uart_prepare_idle(0); - omap_uart_prepare_idle(1); - omap_uart_prepare_idle(2); - /* Jump to SRAM suspend code */ omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL), OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL), OMAP_SDRC_REGADDR(SDRC_POWER)); - omap_uart_resume_idle(2); - omap_uart_resume_idle(1); - omap_uart_resume_idle(0); - - if (!is_suspending()) - console_unlock(); + omap_uart_resume_idle(); no_sleep: if (omap2_pm_debug) { @@ -162,7 +148,7 @@ no_sleep: tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC; omap2_pm_dump(0, 1, tmp); } - omap2_gpio_resume_after_idle(); + omap2_gpio_resume_after_idle(0); clk_enable(osc_ck); @@ -267,8 +253,6 @@ static int omap2_can_sleep(void) { if (omap2_fclks_active()) return 0; - if (!omap_uart_can_sleep()) - return 0; if (osc_ck->usecount > 1) return 0; if (omap_dma_running()) @@ -319,7 +303,6 @@ static int omap2_pm_suspend(void) mir1 = omap_readl(0x480fe0a4); omap_writel(1 << 5, 0x480fe0ac); - omap_uart_prepare_suspend(); omap2_enter_full_retention(); omap_writel(mir1, 0x480fe0a4); @@ -518,6 +501,8 @@ static int __init omap2_pm_init(void) suspend_set_ops(&omap_pm_ops); pm_idle = omap2_pm_idle; + omap_pm_is_ready_status = true; + return 0; } diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index c155c9d..cb1e8d8 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -91,16 +91,6 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; static struct powerdomain *cam_pwrdm; -static inline void omap3_per_save_context(void) -{ - omap_gpio_save_context(); -} - -static inline void omap3_per_restore_context(void) -{ - omap_gpio_restore_context(); -} - static void omap3_enable_io_chain(void) { int timeout = 0; @@ -146,7 +136,7 @@ static void omap3_core_save_context(void) /* Save the Interrupt controller context */ omap_intc_save_context(); /* Save the GPMC context */ - omap3_gpmc_save_context(); + omap_gpmc_save_context(); /* Save the system control module context, padconf already save above*/ omap3_control_save_context(); omap_dma_global_context_save(); @@ -157,7 +147,7 @@ static void omap3_core_restore_context(void) /* Restore the control module context, padconf restored by h/w */ omap3_control_restore_context(); /* Restore the GPMC context */ - omap3_gpmc_restore_context(); + omap_gpmc_restore_context(); /* Restore the interrupt controller context */ omap_intc_restore_context(); omap_dma_global_context_restore(); @@ -216,6 +206,8 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) wkst = omap2_prm_read_mod_reg(module, wkst_off); wkst &= omap2_prm_read_mod_reg(module, grpsel_off); + + c += omap_uart_resume_idle(); if (wkst) { iclk = omap2_cm_read_mod_reg(module, iclk_off); fclk = omap2_cm_read_mod_reg(module, fclk_off); @@ -336,7 +328,7 @@ static void restore_table_entry(void) set_cr(control_reg_value); } -void omap_sram_idle(void) +void omap_sram_idle(bool suspend) { /* Variable to tell what needs to be saved and restored * in omap_sram_idle*/ @@ -375,7 +367,6 @@ void omap_sram_idle(void) printk(KERN_ERR "Invalid mpu state in sram_idle\n"); return; } - pwrdm_pre_transition(); /* NEON control */ if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) @@ -391,27 +382,15 @@ void omap_sram_idle(void) omap3_enable_io_chain(); } - /* Block console output in case it is on one of the OMAP UARTs */ - if (!is_suspending()) - if (per_next_state < PWRDM_POWER_ON || - core_next_state < PWRDM_POWER_ON) - if (!console_trylock()) - goto console_still_active; - + pwrdm_pre_transition(); /* PER */ if (per_next_state < PWRDM_POWER_ON) { per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0; - omap_uart_prepare_idle(2); - omap_uart_prepare_idle(3); - omap2_gpio_prepare_for_idle(per_going_off); - if (per_next_state == PWRDM_POWER_OFF) - omap3_per_save_context(); + omap2_gpio_prepare_for_idle(per_going_off, suspend); } /* CORE */ if (core_next_state < PWRDM_POWER_ON) { - omap_uart_prepare_idle(0); - omap_uart_prepare_idle(1); if (core_next_state == PWRDM_POWER_OFF) { omap3_core_save_context(); omap3_cm_save_context(); @@ -458,8 +437,6 @@ void omap_sram_idle(void) omap3_sram_restore_context(); omap2_sms_restore_context(); } - omap_uart_resume_idle(0); - omap_uart_resume_idle(1); if (core_next_state == PWRDM_POWER_OFF) omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK, OMAP3430_GR_MOD, @@ -467,20 +444,14 @@ void omap_sram_idle(void) } omap3_intc_resume_idle(); + pwrdm_post_transition(); + /* PER */ if (per_next_state < PWRDM_POWER_ON) { per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); - omap2_gpio_resume_after_idle(); - if (per_prev_state == PWRDM_POWER_OFF) - omap3_per_restore_context(); - omap_uart_resume_idle(2); - omap_uart_resume_idle(3); + omap2_gpio_resume_after_idle(per_going_off); } - if (!is_suspending()) - console_unlock(); - -console_still_active: /* Disable IO-PAD and IO-CHAIN wakeup */ if (omap3_has_io_wakeup() && (per_next_state < PWRDM_POWER_ON || @@ -490,8 +461,6 @@ console_still_active: omap3_disable_io_chain(); } - pwrdm_post_transition(); - clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); } @@ -499,8 +468,6 @@ int omap3_can_sleep(void) { if (!sleep_while_idle) return 0; - if (!omap_uart_can_sleep()) - return 0; return 1; } @@ -518,7 +485,7 @@ static void omap3_pm_idle(void) trace_power_start(POWER_CSTATE, 1, smp_processor_id()); trace_cpu_idle(1, smp_processor_id()); - omap_sram_idle(); + omap_sram_idle(false); trace_power_end(smp_processor_id()); trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id()); @@ -549,10 +516,9 @@ static int omap3_pm_suspend(void) goto restore; } - omap_uart_prepare_suspend(); omap3_intc_suspend(); - omap_sram_idle(); + omap_sram_idle(true); restore: /* Restore next_pwrsts */ @@ -596,14 +562,12 @@ static int omap3_pm_begin(suspend_state_t state) { disable_hlt(); suspend_state = state; - omap_uart_enable_irqs(0); return 0; } static void omap3_pm_end(void) { suspend_state = PM_SUSPEND_ON; - omap_uart_enable_irqs(1); enable_hlt(); return; } @@ -956,6 +920,7 @@ static int __init omap3_pm_init(void) } omap3_save_scratchpad_contents(); + omap_pm_is_ready_status = true; err1: return ret; err2: diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 59a870b..b9e2bf1 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -1,8 +1,9 @@ /* * OMAP4 Power Management Routines * - * Copyright (C) 2010 Texas Instruments, Inc. + * Copyright (C) 2010-2011 Texas Instruments, Inc. * Rajendra Nayak <rnayak@ti.com> + * Santosh Shilimkar <santosh.shilimkar@ti.com> * * 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 @@ -12,28 +13,713 @@ #include <linux/pm.h> #include <linux/suspend.h> #include <linux/module.h> +#include <linux/clk.h> #include <linux/list.h> #include <linux/err.h> #include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/irq.h> -#include "powerdomain.h" +#include <asm/hardware/gic.h> #include <mach/omap4-common.h> +#include <plat/omap_hsi.h> +#include <plat/common.h> +#include <plat/temperature_sensor.h> +#include <plat/usb.h> +#include <plat/prcm.h> +#include <plat/omap-pm.h> +#include <plat/gpmc.h> +#include <plat/dma.h> + +#include <mach/omap_fiq_debugger.h> + +#include "powerdomain.h" +#include "clockdomain.h" +#include "pm.h" +#include "prm-regbits-44xx.h" +#include "prcm44xx.h" +#include "prm44xx.h" +#include "prminst44xx.h" +#include "clock.h" +#include "cm2_44xx.h" +#include "cm1_44xx.h" +#include "cm44xx.h" +#include "cm-regbits-44xx.h" +#include "cminst44xx.h" +#include "scrm44xx.h" +#include "prcm-debug.h" + +#include "smartreflex.h" +#include "dvfs.h" +#include "voltage.h" +#include "vc.h" +#include "control.h" struct power_state { struct powerdomain *pwrdm; u32 next_state; #ifdef CONFIG_SUSPEND u32 saved_state; + u32 saved_logic_state; #endif struct list_head node; }; static LIST_HEAD(pwrst_list); +static struct powerdomain *mpu_pwrdm, *cpu0_pwrdm; +static struct powerdomain *core_pwrdm, *per_pwrdm; + +static struct voltagedomain *mpu_voltdm, *iva_voltdm, *core_voltdm; + +static struct clockdomain *tesla_clkdm; +static struct powerdomain *tesla_pwrdm; + +static struct clockdomain *emif_clkdm, *mpuss_clkdm; + +/* Yet un-named erratum which requires AUTORET to be disabled for IVA PD */ +#define OMAP4_PM_ERRATUM_IVA_AUTO_RET_iXXX BIT(1) + +/* Dynamic dependendency Cannot be enabled due to i688 erratum ID for 443x */ +#define OMAP4_PM_ERRATUM_MPU_EMIF_NO_DYNDEP_i688 BIT(3) +/* + * Dynamic dependendency Cannot be enabled due to i688 erratum ID for above 443x + * NOTE: this is NOT YET a confirmed erratum for 446x, but provided here in + * anticipation. + * If a fix is found at a later date, the code using this can be removed. + * WA involves: + * Enable MPU->EMIF SD before WFI and disable while coming out of WFI. + * This works around system hang/lockups seen when only MPU->EMIF + * dynamic dependency set. Allows dynamic dependency to be used + * in all active usecases and get all the power savings accordingly. + * TODO: Once this is available as final Errata, update with proper + * fix. + */ +#define OMAP4_PM_ERRATUM_MPU_EMIF_NO_DYNDEP_IDLE_iXXX BIT(4) + +static u8 pm44xx_errata; +#define is_pm44xx_erratum(erratum) (pm44xx_errata & OMAP4_PM_ERRATUM_##erratum) + +#define MAX_IOPAD_LATCH_TIME 1000 +void omap4_trigger_ioctrl(void) +{ + int i = 0; + + /* Enable GLOBAL_WUEN */ + if (!omap4_cminst_read_inst_reg_bits(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET, + OMAP4430_GLOBAL_WUEN_MASK)) + omap4_prminst_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK, + OMAP4430_GLOBAL_WUEN_MASK, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET); + + /* Trigger WUCLKIN enable */ + omap4_prminst_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK, OMAP4430_WUCLK_CTRL_MASK, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET); + omap_test_timeout((((omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, + OMAP4_PRM_IO_PMCTRL_OFFSET) & + OMAP4430_WUCLK_STATUS_MASK) >> + OMAP4430_WUCLK_STATUS_SHIFT) == 1), + MAX_IOPAD_LATCH_TIME, i); + if (i == MAX_IOPAD_LATCH_TIME) + pr_err("%s: Max IO latch time reached for WUCLKIN enable\n", + __func__); + + /* Trigger WUCLKIN disable */ + omap4_prminst_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK, 0x0, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET); + + /* Ensure this is cleared */ + omap_test_timeout((((omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, + OMAP4_PRM_IO_PMCTRL_OFFSET) & + OMAP4430_WUCLK_STATUS_MASK) >> + OMAP4430_WUCLK_STATUS_SHIFT) == 0), + MAX_IOPAD_LATCH_TIME, i); + if (i == MAX_IOPAD_LATCH_TIME) + pr_err("%s: Max IO latch time reached for WUCLKIN disable\n", + __func__); + return; +} #ifdef CONFIG_SUSPEND +/* This is a common low power function called from suspend and + * cpuidle + */ + +void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, bool suspend) +{ + int cpu0_next_state = PWRDM_POWER_ON; + int per_next_state = PWRDM_POWER_ON; + int core_next_state = PWRDM_POWER_ON; + int mpu_next_state = PWRDM_POWER_ON; + int ret; + int staticdep_wa_applied = 0; + + pwrdm_clear_all_prev_pwrst(cpu0_pwrdm); + pwrdm_clear_all_prev_pwrst(mpu_pwrdm); + pwrdm_clear_all_prev_pwrst(core_pwrdm); + pwrdm_clear_all_prev_pwrst(per_pwrdm); + omap4_device_clear_prev_off_state(); + + /* + * Just return if we detect a scenario where we conflict + * with DVFS + */ + if (omap_dvfs_is_any_dev_scaling()) + return; + + cpu0_next_state = pwrdm_read_next_pwrst(cpu0_pwrdm); + per_next_state = pwrdm_read_next_pwrst(per_pwrdm); + core_next_state = pwrdm_read_next_pwrst(core_pwrdm); + mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); + + ret = omap2_gpio_prepare_for_idle(omap4_device_next_state_off(), suspend); + if (ret) + goto abort_gpio; + + if (is_pm44xx_erratum(MPU_EMIF_NO_DYNDEP_IDLE_iXXX) && + mpu_next_state <= PWRDM_POWER_INACTIVE) { + /* Configures MEMIF clockdomain in SW_WKUP */ + if (clkdm_wakeup(emif_clkdm)) { + pr_err("%s: Failed to force wakeup of %s\n", + __func__, emif_clkdm->name); + } else { + /* Enable MPU-EMIF Static Dependency around WFI */ + if (clkdm_add_wkdep(mpuss_clkdm, emif_clkdm)) + pr_err("%s: Failed to Add wkdep %s->%s\n", + __func__, mpuss_clkdm->name, + emif_clkdm->name); + else + staticdep_wa_applied = 1; + + /* Configures MEMIF clockdomain back to HW_AUTO */ + clkdm_allow_idle(emif_clkdm); + } + } + if (mpu_next_state < PWRDM_POWER_INACTIVE) { + if (omap_sr_disable_reset_volt(mpu_voltdm)) + goto abort_device_off; + + omap_sr_disable_reset_volt(mpu_voltdm); + omap_vc_set_auto_trans(mpu_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_RETENTION); + } + + if (core_next_state < PWRDM_POWER_ON) { + /* + * Note: IVA can hit RET outside of cpuidle and hence this is + * not the right optimal place to enable IVA AUTO RET. But since + * enabling AUTO RET requires SR to disabled, its done here for + * now. Needs a relook to see if this can be optimized. + */ + if (omap_sr_disable_reset_volt(iva_voltdm)) + goto abort_device_off; + if (omap_sr_disable_reset_volt(core_voltdm)) + goto abort_device_off; + omap_vc_set_auto_trans(core_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_RETENTION); + if (!is_pm44xx_erratum(IVA_AUTO_RET_iXXX)) { + omap_vc_set_auto_trans(iva_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_RETENTION); + } + + omap_temp_sensor_prepare_idle(); + } + + if (omap4_device_next_state_off()) { + omap_gpmc_save_context(); + omap_dma_global_context_save(); + } + + if (suspend && cpu_is_omap44xx()) + omap4_pm_suspend_save_regs(); + + if (omap4_device_next_state_off()) { + /* Save the device context to SAR RAM */ + if (omap4_sar_save()) + goto abort_device_off; + omap4_sar_overwrite(); + omap4_cm_prepare_off(); + omap4_dpll_prepare_off(); + + /* Extend Non-EMIF I/O isolation */ + omap4_prminst_rmw_inst_reg_bits(OMAP4430_ISOOVR_EXTEND_MASK, + OMAP4430_ISOOVR_EXTEND_MASK, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET); + } + + omap4_enter_lowpower(cpu, power_state); + + if (omap4_device_prev_state_off()) { + /* Reconfigure the trim settings as well */ + omap4_ldo_trim_configure(); + omap4_dpll_resume_off(); + omap4_cm_resume_off(); +#ifdef CONFIG_PM_DEBUG + omap4_device_off_counter++; +#endif + } + +abort_device_off: + if (core_next_state < PWRDM_POWER_ON) { + /* See note above */ + omap_vc_set_auto_trans(core_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE); + if (!is_pm44xx_erratum(IVA_AUTO_RET_iXXX)) { + omap_vc_set_auto_trans(iva_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE); + } + + omap_temp_sensor_resume_idle(); + omap_sr_enable(iva_voltdm, + omap_voltage_get_curr_vdata(iva_voltdm)); + omap_sr_enable(core_voltdm, + omap_voltage_get_curr_vdata(core_voltdm)); + } + + if (omap4_device_prev_state_off()) { + omap_dma_global_context_restore(); + omap_gpmc_restore_context(); + } + + omap2_gpio_resume_after_idle(omap4_device_next_state_off()); + + if (omap4_device_next_state_off()) { + /* Disable the extension of Non-EMIF I/O isolation */ + omap4_prminst_rmw_inst_reg_bits(OMAP4430_ISOOVR_EXTEND_MASK, + 0, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET); + } + + if (mpu_next_state < PWRDM_POWER_INACTIVE) { + omap_vc_set_auto_trans(mpu_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE); + omap_sr_enable(mpu_voltdm, + omap_voltage_get_curr_vdata(mpu_voltdm)); + } + + /* + * NOTE: is_pm44xx_erratum is not strictly required, but retained for + * code context redability. + */ + if (is_pm44xx_erratum(MPU_EMIF_NO_DYNDEP_IDLE_iXXX) && + staticdep_wa_applied) { + /* Configures MEMIF clockdomain in SW_WKUP */ + if (clkdm_wakeup(emif_clkdm)) + pr_err("%s: Failed to force wakeup of %s\n", + __func__, emif_clkdm->name); + /* Disable MPU-EMIF Static Dependency on WFI exit */ + else if (clkdm_del_wkdep(mpuss_clkdm, emif_clkdm)) + pr_err("%s: Failed to remove wkdep %s->%s\n", + __func__, mpuss_clkdm->name, + emif_clkdm->name); + /* Configures MEMIF clockdomain back to HW_AUTO */ + clkdm_allow_idle(emif_clkdm); + } + +abort_gpio: + return; +} + +#ifdef CONFIG_PM_DEBUG +#define GPIO_BANKS 6 +#define MODULEMODE_DISABLED 0x0 +#define MODULEMODE_AUTO 0x1 + +static void _print_wakeirq(int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + + if (irq == OMAP44XX_IRQ_LOCALTIMER) + pr_info("Resume caused by IRQ %d, localtimer\n", irq); + else if (!desc || !desc->action || !desc->action->name) + pr_info("Resume caused by IRQ %d\n", irq); + else + pr_info("Resume caused by IRQ %d, %s\n", irq, + desc->action->name); +} + +static void _print_gpio_wakeirq(int irq) +{ + int bank = irq - OMAP44XX_IRQ_GPIO1; + int bit; + int gpioirq; + int restoremod = 0; + int timeout = 10; + u32 wken, irqst, gpio; + u32 clkctrl; + long unsigned int wkirqs; + void *gpio_base[GPIO_BANKS] = { + OMAP2_L4_IO_ADDRESS(0x4a310000), + OMAP2_L4_IO_ADDRESS(0x48055000), + OMAP2_L4_IO_ADDRESS(0x48057000), + OMAP2_L4_IO_ADDRESS(0x48059000), + OMAP2_L4_IO_ADDRESS(0x4805b000), + OMAP2_L4_IO_ADDRESS(0x4805d000), + }; + void *gpio_clkctrl[GPIO_BANKS] = { + OMAP4430_CM_WKUP_GPIO1_CLKCTRL, + OMAP4430_CM_L4PER_GPIO2_CLKCTRL, + OMAP4430_CM_L4PER_GPIO3_CLKCTRL, + OMAP4430_CM_L4PER_GPIO4_CLKCTRL, + OMAP4430_CM_L4PER_GPIO5_CLKCTRL, + OMAP4430_CM_L4PER_GPIO6_CLKCTRL, + }; + + /* + * GPIO1 is in CD_WKUP. + * GPIO2-6 are in CD_l4_PER. + * + * Both of these clock domains are static dependencies of + * the MPUSS clock domain (CD_CORTEXA9) and are guaranteed + * to be already enabled (_CLKSTCTRL.CLKTRCTRL = HW_AUTO). + * + * Ensure the GPIO module is enabled (_CLKCTRL.MODULEMODE = + * h/w managed). If not, will set it back to disabled when + * done. + */ + + clkctrl = __raw_readl(gpio_clkctrl[bank]); + + if ((clkctrl & OMAP4430_MODULEMODE_MASK) != + MODULEMODE_AUTO << OMAP4430_MODULEMODE_SHIFT) { + restoremod = 1; + __raw_writel((clkctrl & ~(OMAP4430_MODULEMODE_MASK)) | + MODULEMODE_AUTO << OMAP4430_MODULEMODE_SHIFT, + gpio_clkctrl[bank]); + + while ((__raw_readl(gpio_clkctrl[bank]) & + OMAP4430_MODULEMODE_MASK) != + MODULEMODE_AUTO << OMAP4430_MODULEMODE_SHIFT && + --timeout) + udelay(5); + + if (!timeout) + goto punt; + } + + wken = __raw_readl(gpio_base[bank] + OMAP4_GPIO_IRQWAKEN0); + irqst = __raw_readl(gpio_base[bank] + OMAP4_GPIO_IRQSTATUS0); + wkirqs = irqst & wken; + + if (!wkirqs) + wkirqs = irqst; + + if (!wkirqs) + goto punt; + + for_each_set_bit(bit, &wkirqs, 32) { + gpio = bit + bank * 32; + gpioirq = gpio_to_irq(gpio); + + if (gpioirq < 0) + pr_info("Resume caused by GPIO %d\n", (int)gpio); + else + _print_wakeirq(gpioirq); + } + + goto out; + +punt: + pr_info("Resume caused by IRQ %d, unknown GPIO%d interrupt\n", irq, + bank + 1); + +out: + if (restoremod) + __raw_writel(clkctrl, gpio_clkctrl[bank]); +} + +#define CONTROL_PADCONF_WAKEUPEVENT_0 0x4a1001d8 +#define CONTROL_WKUP_PADCONF_WAKEUPEVENT_0 0x4a31E07C + +static void _print_prcm_wakeirq(int irq) +{ + int i, bit; + int iopad_wake_found = 0; + u32 prcm_irqs1, prcm_irqs2; + long unsigned int wkup_pad_event; + + prcm_irqs1 = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, + OMAP4_PRM_IRQSTATUS_MPU_OFFSET); + prcm_irqs1 &= omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, + OMAP4_PRM_IRQENABLE_MPU_OFFSET); + prcm_irqs2 = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, + OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET); + prcm_irqs2 &= omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, + OMAP4_PRM_IRQENABLE_MPU_2_OFFSET); + + if (prcm_irqs1 & OMAP4430_IO_ST_MASK) { + for (i = 0; i <= 6; i++) { + long unsigned int wkevt = + omap_readl(CONTROL_PADCONF_WAKEUPEVENT_0 + i*4); + + for_each_set_bit(bit, &wkevt, 32) { + pr_info("Resume caused by I/O pad: CONTROL_PADCONF_WAKEUPEVENT_%d[%d]\n", + i, bit); + iopad_wake_found = 1; + } + } + wkup_pad_event = omap_readl(CONTROL_WKUP_PADCONF_WAKEUPEVENT_0); + for_each_set_bit(bit, &wkup_pad_event, 25) { + pr_info("Resume caused by wakeup I/O pad: CONTROL_WKUP_PADCONF_WAKEUPEVENT_0[%d]\n", bit); + iopad_wake_found = 1; + } + } + + if (prcm_irqs1 & ~OMAP4430_IO_ST_MASK || !iopad_wake_found || + prcm_irqs2) + pr_info("Resume caused by IRQ %d, prcm: 0x%x 0x%x\n", irq, + prcm_irqs1, prcm_irqs2); +} + +static void omap4_print_wakeirq(void) +{ + int irq; + + irq = gic_cpu_read(GIC_CPU_HIGHPRI) & 0x3ff; + + if ((irq == 1022) || (irq == 1023)) { + pr_info("GIC returns spurious interrupt for resume IRQ\n"); + return; + } + + if (irq >= OMAP44XX_IRQ_GPIO1 && + irq <= OMAP44XX_IRQ_GPIO1 + GPIO_BANKS - 1) + _print_gpio_wakeirq(irq); + else if (irq == OMAP44XX_IRQ_PRCM) + _print_prcm_wakeirq(irq); + else + _print_wakeirq(irq); +} +#else +static void omap4_print_wakeirq(void) +{ +} +#endif + +/** + * get_achievable_state() - Provide achievable state + * @available_states: what states are available + * @req_min_state: what state is the minimum we'd like to hit + * @is_parent_pd: is this a parent power domain? + * + * Power domains have varied capabilities. When attempting a low power + * state such as OFF/RET, a specific min requested state may not be + * supported on the power domain, in which case: + * a) if this power domain is a parent power domain, we do not intend + * for it to go to a lower power state(because we are not targetting it), + * select the next higher power state which is supported is returned. + * b) However, for all children power domains, we first try to match + * with a lower power domain state before attempting a higher state. + * This is because a combination of system power states where the + * parent PD's state is not in line with expectation can result in + * system instabilities. + */ +static inline u8 get_achievable_state(u8 available_states, u8 req_min_state, + bool is_parent_pd) +{ + u8 max_mask = 0xFF << req_min_state; + u8 min_mask = ~max_mask; + + /* First see if we have an accurate match */ + if (available_states & BIT(req_min_state)) + return req_min_state; + + /* See if a lower power state is possible on this child domain */ + if (!is_parent_pd && available_states & min_mask) + return __ffs(available_states & min_mask); + + if (available_states & max_mask) + return __ffs(available_states & max_mask); + + return PWRDM_POWER_ON; +} + +/** + * omap4_configure_pwdm_suspend() - Program powerdomain on suspend + * @is_off_mode: is this an OFF mode transition? + * + * Program all powerdomain to required power domain state: This logic + * Takes the requested mode -OFF/RET translates it to logic and power + * states. This then walks down the power domain states to program + * each domain to the state requested. if the requested state is not + * available, it will check for the higher state. + */ +static void omap4_configure_pwdm_suspend(bool is_off_mode) +{ + struct power_state *pwrst; + u32 state; + u32 logic_state, als; + +#ifdef CONFIG_OMAP_ALLOW_OSWR + if (is_off_mode) { + state = PWRDM_POWER_OFF; + logic_state = PWRDM_POWER_OFF; + } else { + state = PWRDM_POWER_RET; + logic_state = PWRDM_POWER_OFF; + } +#else + state = PWRDM_POWER_RET; + logic_state = PWRDM_POWER_RET; +#endif + + list_for_each_entry(pwrst, &pwrst_list, node) { + bool parent_power_domain = false; + + pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); + pwrst->saved_logic_state = pwrdm_read_logic_retst(pwrst->pwrdm); + + if ((!strcmp(pwrst->pwrdm->name, "cpu0_pwrdm")) || + (!strcmp(pwrst->pwrdm->name, "cpu1_pwrdm"))) + continue; + if (!strcmp(pwrst->pwrdm->name, "core_pwrdm") || + !strcmp(pwrst->pwrdm->name, "mpu_pwrdm") || + !strcmp(pwrst->pwrdm->name, "iva_pwrdm")) + parent_power_domain = true; + /* + * Write only to registers which are writable! Don't touch + * read-only/reserved registers. If pwrdm->pwrsts_logic_ret or + * pwrdm->pwrsts are 0, consider those power domains containing + * readonly/reserved registers which cannot be controlled by + * software. + */ + if (pwrst->pwrdm->pwrsts_logic_ret) { + als = + get_achievable_state(pwrst->pwrdm->pwrsts_logic_ret, + logic_state, parent_power_domain); + if (als < pwrst->saved_logic_state) + pwrdm_set_logic_retst(pwrst->pwrdm, als); + } + if (pwrst->pwrdm->pwrsts) { + pwrst->next_state = + get_achievable_state(pwrst->pwrdm->pwrsts, state, + parent_power_domain); + if (pwrst->next_state < pwrst->saved_state) + omap_set_pwrdm_state(pwrst->pwrdm, + pwrst->next_state); + else + pwrst->next_state = pwrst->saved_state; + } + } +} + +/** + * omap4_restore_pwdms_after_suspend() - Restore powerdomains after suspend + * + * Re-program all powerdomains to saved power domain states. + * + * returns 0 if all power domains hit targeted power state, -1 if any domain + * failed to hit targeted power state (status related to the actual restore + * is not returned). + */ +static int omap4_restore_pwdms_after_suspend(void) +{ + struct power_state *pwrst; + int cstate, pstate, ret = 0; + + /* Restore next powerdomain state */ + list_for_each_entry(pwrst, &pwrst_list, node) { + cstate = pwrdm_read_pwrst(pwrst->pwrdm); + pstate = pwrdm_read_prev_pwrst(pwrst->pwrdm); + if (pstate > pwrst->next_state) { + pr_info("Powerdomain (%s) didn't enter " + "target state %d Vs achieved state %d. " + "current state %d\n", + pwrst->pwrdm->name, pwrst->next_state, + pstate, cstate); + ret = -1; + } + + /* If state already ON due to h/w dep, don't do anything */ + if (cstate == PWRDM_POWER_ON) + continue; + + /* If we have already achieved saved state, nothing to do */ + if (cstate == pwrst->saved_state) + continue; + + /* mpuss code takes care of this */ + if ((!strcmp(pwrst->pwrdm->name, "cpu0_pwrdm")) || + (!strcmp(pwrst->pwrdm->name, "cpu1_pwrdm"))) + continue; + + /* + * Skip pd program if saved state higher than current state + * Since we would have already returned if the state + * was ON, if the current state is yet another low power + * state, the PRCM specification clearly states that + * transition from a lower LP state to a higher LP state + * is forbidden. + */ + if (pwrst->saved_state > cstate) + continue; + + if (pwrst->pwrdm->pwrsts) + omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); + + if (pwrst->pwrdm->pwrsts_logic_ret) + pwrdm_set_logic_retst(pwrst->pwrdm, + pwrst->saved_logic_state); + } + + return ret; +} + static int omap4_pm_suspend(void) { - do_wfi(); + int ret = 0; + + /* + * If any device was in the middle of a scale operation + * then abort, as we cannot predict which part of the scale + * operation we interrupted. + */ + if (omap_dvfs_is_any_dev_scaling()) { + pr_err("%s: oops.. middle of scale op.. aborting suspend\n", + __func__); + return -EBUSY; + } + + /* Wakeup timer from suspend */ + if (wakeup_timer_seconds || wakeup_timer_milliseconds) + omap2_pm_wakeup_on_timer(wakeup_timer_seconds, + wakeup_timer_milliseconds); + + omap4_configure_pwdm_suspend(off_mode_enabled); + + /* Enable Device OFF */ + if (off_mode_enabled) + omap4_device_set_state_off(1); + + /* + * For MPUSS to hit power domain retention(CSWR or OSWR), + * CPU0 and CPU1 power domain needs to be in OFF or DORMANT + * state. For MPUSS to reach off-mode. CPU0 and CPU1 power domain + * should be in off state. + * Only master CPU followes suspend path. All other CPUs follow + * cpu-hotplug path in system wide suspend. On OMAP4, CPU power + * domain CSWR is not supported by hardware. + * More details can be found in OMAP4430 TRM section 4.3.4.2. + */ + omap4_enter_sleep(0, PWRDM_POWER_OFF, true); + omap4_print_wakeirq(); + prcmdebug_dump(PRCMDEBUG_LASTSLEEP); + + /* Disable Device OFF state*/ + if (off_mode_enabled) + omap4_device_set_state_off(0); + + ret = omap4_restore_pwdms_after_suspend(); + + if (ret) + pr_err("Could not enter target state in pm_suspend\n"); + else + pr_err("Successfully put all powerdomains to target state\n"); + return 0; } @@ -71,8 +757,55 @@ static const struct platform_suspend_ops omap_pm_ops = { .enter = omap4_pm_enter, .valid = suspend_valid_only_mem, }; +#else +void omap4_enter_sleep(unsigned int cpu, unsigned int power_state){ return; } #endif /* CONFIG_SUSPEND */ +/** + * omap4_pm_cold_reset() - Cold reset OMAP4 + * @reason: why am I resetting. + * + * As per the TRM, it is recommended that we set all the power domains to + * ON state before we trigger cold reset. + */ +int omap4_pm_cold_reset(char *reason) +{ + struct power_state *pwrst; + + /* Switch ON all pwrst registers */ + list_for_each_entry(pwrst, &pwrst_list, node) { + if (pwrst->pwrdm->pwrsts_logic_ret) + pwrdm_set_logic_retst(pwrst->pwrdm, PWRDM_POWER_ON); + if (pwrst->pwrdm->pwrsts) + omap_set_pwrdm_state(pwrst->pwrdm, PWRDM_POWER_ON); + } + + WARN(1, "Arch Cold reset has been triggered due to %s\n", reason); + omap4_prm_global_cold_sw_reset(); /* never returns */ + + /* If we reached here - something bad went on.. */ + BUG(); + + /* make the compiler happy */ + return -EINTR; +} + +/* + * Enable hardware supervised mode for all clockdomains if it's + * supported. Initiate sleep transition for other clockdomains, if + * they are not used + */ +static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) +{ + if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) + clkdm_allow_idle(clkdm); + else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && + atomic_read(&clkdm->usecount) == 0) + clkdm_sleep(clkdm); + return 0; +} + + static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) { struct power_state *pwrst; @@ -83,11 +816,397 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC); if (!pwrst) return -ENOMEM; + pwrst->pwrdm = pwrdm; - pwrst->next_state = PWRDM_POWER_ON; + if ((!strcmp(pwrdm->name, "mpu_pwrdm")) || + (!strcmp(pwrdm->name, "core_pwrdm")) || + (!strcmp(pwrdm->name, "cpu0_pwrdm")) || + (!strcmp(pwrdm->name, "cpu1_pwrdm"))) + pwrst->next_state = PWRDM_POWER_ON; + else + pwrst->next_state = PWRDM_POWER_RET; list_add(&pwrst->node, &pwrst_list); - return pwrdm_set_next_pwrst(pwrst->pwrdm, pwrst->next_state); + return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state); +} + +static int __init _voltdm_sum_time(struct voltagedomain *voltdm, void *user) +{ + struct omap_voltdm_pmic *pmic; + u32 *max_time = (u32 *)user; + + if (!voltdm || !max_time) { + WARN_ON(1); + return -EINVAL; + } + + pmic = voltdm->pmic; + if (pmic) { + *max_time += pmic->on_volt / pmic->slew_rate; + *max_time += pmic->switch_on_time; + } + + return 0; +} + +static u32 __init _usec_to_val_scrm(unsigned long rate, u32 usec, + u32 shift, u32 mask) +{ + u32 val; + + /* limit to max value */ + val = ((mask >> shift) * 1000000) / rate; + if (usec > val) + usec = val; + + /* convert the time in usec to cycles */ + val = DIV_ROUND_UP(rate * usec, 1000000); + return (val << shift) & mask; + +} + +static void __init syscontrol_setup_regs(void) +{ + u32 v; + + /* Disable LPDDR VREF manual control and enable Auto control */ + v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_3); + v &= ~(OMAP4_LPDDR21_VREF_EN_CA_MASK | OMAP4_LPDDR21_VREF_EN_DQ_MASK); + v |= OMAP4_LPDDR21_VREF_AUTO_EN_CA_MASK | OMAP4_LPDDR21_VREF_AUTO_EN_DQ_MASK; + omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_3); + + v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_3); + v &= ~(OMAP4_LPDDR21_VREF_EN_CA_MASK | OMAP4_LPDDR21_VREF_EN_DQ_MASK); + v |= OMAP4_LPDDR21_VREF_AUTO_EN_CA_MASK | OMAP4_LPDDR21_VREF_AUTO_EN_DQ_MASK; + omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_3); + + /* + * Workaround for CK differential IO PADn, PADp values due to bug in + * EMIF CMD phy. + */ + v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2); + v &= ~OMAP4_LPDDR2IO1_GR10_WD_MASK; + omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2); + v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2); + v &= ~OMAP4_LPDDR2IO2_GR10_WD_MASK; + omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2); +} + +static void __init prcm_setup_regs(void) +{ + struct clk *clk32k = clk_get(NULL, "sys_32k_ck"); + unsigned long rate32k = 0; + u32 val, tshut, tstart; + u32 reset_delay_time = 0; + + if (clk32k) { + rate32k = clk_get_rate(clk32k); + clk_put(clk32k); + } else { + pr_err("%s: no 32k clk!!!\n", __func__); + dump_stack(); + } + + /* Enable IO_ST interrupt */ + omap4_prminst_rmw_inst_reg_bits(OMAP4430_IO_ST_MASK, OMAP4430_IO_ST_MASK, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_PRM_IRQENABLE_MPU_OFFSET); + + /* + * Errata ID: i608 Impacted OMAP4430 ES 1.0,2.0,2.1,2.2 + * On OMAP4, Retention-Till-Access Memory feature is not working + * reliably and hardware recommondation is keep it disabled by + * default + */ + omap4_prminst_rmw_inst_reg_bits(OMAP4430_DISABLE_RTA_EXPORT_MASK, + 0x1 << OMAP4430_DISABLE_RTA_EXPORT_SHIFT, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_SRAM_WKUP_SETUP_OFFSET); + omap4_prminst_rmw_inst_reg_bits(OMAP4430_DISABLE_RTA_EXPORT_MASK, + 0x1 << OMAP4430_DISABLE_RTA_EXPORT_SHIFT, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_LDO_SRAM_CORE_SETUP_OFFSET); + omap4_prminst_rmw_inst_reg_bits(OMAP4430_DISABLE_RTA_EXPORT_MASK, + 0x1 << OMAP4430_DISABLE_RTA_EXPORT_SHIFT, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_LDO_SRAM_MPU_SETUP_OFFSET); + omap4_prminst_rmw_inst_reg_bits(OMAP4430_DISABLE_RTA_EXPORT_MASK, + 0x1 << OMAP4430_DISABLE_RTA_EXPORT_SHIFT, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_LDO_SRAM_IVA_SETUP_OFFSET); + + /* Allow SRAM LDO to enter RET during low power state*/ + if (cpu_is_omap446x()) { + omap4_prminst_rmw_inst_reg_bits(OMAP4430_RETMODE_ENABLE_MASK, + 0x1 << OMAP4430_RETMODE_ENABLE_SHIFT, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_LDO_SRAM_CORE_CTRL_OFFSET); + omap4_prminst_rmw_inst_reg_bits(OMAP4430_RETMODE_ENABLE_MASK, + 0x1 << OMAP4430_RETMODE_ENABLE_SHIFT, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_LDO_SRAM_MPU_CTRL_OFFSET); + omap4_prminst_rmw_inst_reg_bits(OMAP4430_RETMODE_ENABLE_MASK, + 0x1 << OMAP4430_RETMODE_ENABLE_SHIFT, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_LDO_SRAM_IVA_CTRL_OFFSET); + } + /* Toggle CLKREQ in RET and OFF states */ + omap4_prminst_write_inst_reg(0x2, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_CLKREQCTRL_OFFSET); + + if (!rate32k) + goto no_32k; + + /* Setup max clksetup time for oscillator */ + omap_pm_get_osc_lp_time(&tstart, &tshut); + val = _usec_to_val_scrm(rate32k, tstart, OMAP4_SETUPTIME_SHIFT, + OMAP4_SETUPTIME_MASK); + val |= _usec_to_val_scrm(rate32k, tshut, OMAP4_DOWNTIME_SHIFT, + OMAP4_DOWNTIME_MASK); + omap4_prminst_write_inst_reg(val, OMAP4430_SCRM_PARTITION, 0x0, + OMAP4_SCRM_CLKSETUPTIME_OFFSET); + + /* + * Setup OMAP WARMRESET time: + * we use the sum of each voltage domain setup times to handle + * the worst case condition where the device resets from OFF mode. + * hence we leave PRM_VOLTSETUP_WARMRESET alone as this is + * already part of RSTTIME1 we program in. + * in addition, to handle oscillator switch off and switch back on + * (in case WDT triggered while CLKREQ goes low), we also + * add in the additional latencies. + */ + if (!voltdm_for_each(_voltdm_sum_time, (void *)&reset_delay_time)) { + reset_delay_time += tstart + tshut; + val = _usec_to_val_scrm(rate32k, reset_delay_time, + OMAP4430_RSTTIME1_SHIFT, OMAP4430_RSTTIME1_MASK); + omap4_prminst_rmw_inst_reg_bits(OMAP4430_RSTTIME1_MASK, val, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, + OMAP4_PRM_RSTTIME_OFFSET); + } + + /* Setup max PMIC startup time */ + omap_pm_get_pmic_lp_time(&tstart, &tshut); + val = _usec_to_val_scrm(rate32k, tstart, OMAP4_WAKEUPTIME_SHIFT, + OMAP4_WAKEUPTIME_MASK); + val |= _usec_to_val_scrm(rate32k, tshut, OMAP4_SLEEPTIME_SHIFT, + OMAP4_SLEEPTIME_MASK); + omap4_prminst_write_inst_reg(val, OMAP4430_SCRM_PARTITION, 0x0, + OMAP4_SCRM_PMICSETUPTIME_OFFSET); + +no_32k: + /* + * De-assert PWRREQ signal in Device OFF state + * 0x3: PWRREQ is de-asserted if all voltage domain are in + * OFF state. Conversely, PWRREQ is asserted upon any + * voltage domain entering or staying in ON or SLEEP or + * RET state. + */ + omap4_prminst_write_inst_reg(0x3, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_PWRREQCTRL_OFFSET); + +} + + +/* omap_pm_clear_dsp_wake_up - SW WA for hardcoded wakeup dependency +* from HSI to DSP +* +* Due to HW bug, same SWakeup signal is used for both MPU and DSP. +* Thus Swakeup will unexpectedly wakeup the DSP domain even if nothing runs on +* DSP. Since MPU is faster to process SWakeup, it acknowledges the Swakeup to +* HSI before the DSP has completed its domain transition. This leaves the DSP +* Power Domain in INTRANSITION state forever, and prevents the DEVICE-OFF mode. +* +* Workaround consists in : +* when a SWakeup is asserted from HSI to MPU (and DSP) : +* - force a DSP SW wakeup +* - wait DSP module to be fully ON +* - Configure a DSP CLK CTRL to HW_AUTO +* - Wait on DSP module to be OFF +* +* Note : we detect a Swakeup is asserted to MPU by checking when an interrupt +* is received while HSI module is ON. +* +* Bug ref is HSI-C1BUG00106 : dsp swakeup generated by HSI same as mpu swakeup +*/ +static void omap_pm_clear_dsp_wake_up(void) +{ + int ret; + int timeout = 10; + + if (!tesla_pwrdm || !tesla_clkdm) { + WARN_ONCE(1, "%s: unable to use tesla workaround\n", __func__); + return; + } + + ret = pwrdm_read_pwrst(tesla_pwrdm); + /* + * If current Tesla power state is in RET/OFF and not in transition, + * then not hit by errata. + */ + if (ret <= PWRDM_POWER_RET) { + if (!(omap4_prminst_read_inst_reg(tesla_pwrdm->prcm_partition, + tesla_pwrdm->prcm_offs, OMAP4_PM_PWSTST) + & OMAP_INTRANSITION_MASK)) + return; + } + + if (clkdm_wakeup(tesla_clkdm)) + pr_err("%s: Failed to force wakeup of %s\n", __func__, + tesla_clkdm->name); + + /* This takes less than a few microseconds, hence in context */ + pwrdm_wait_transition(tesla_pwrdm); + + /* + * Check current power state of Tesla after transition, to make sure + * that Tesla is indeed turned ON. + */ + ret = pwrdm_read_pwrst(tesla_pwrdm); + do { + pwrdm_wait_transition(tesla_pwrdm); + ret = pwrdm_read_pwrst(tesla_pwrdm); + } while ((ret < PWRDM_POWER_INACTIVE) && --timeout); + + if (!timeout) + pr_err("%s: Tesla failed to transition to ON state!\n", + __func__); + + timeout = 10; + clkdm_allow_idle(tesla_clkdm); + + /* Ensure Tesla power state in OFF state */ + ret = pwrdm_read_pwrst(tesla_pwrdm); + do { + pwrdm_wait_transition(tesla_pwrdm); + ret = pwrdm_read_pwrst(tesla_pwrdm); + } while ((ret >= PWRDM_POWER_INACTIVE) && --timeout); + + if (!timeout) + pr_err("%s: Tesla failed to transition to OFF state\n", + __func__); + +} + +static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) +{ + u32 irqenable_mpu, irqstatus_mpu; + + irqenable_mpu = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, + OMAP4_PRM_IRQENABLE_MPU_OFFSET); + irqstatus_mpu = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, + OMAP4_PRM_IRQSTATUS_MPU_OFFSET); + + /* Check if a IO_ST interrupt */ + if (irqstatus_mpu & OMAP4430_IO_ST_MASK) { + /* Check if HSI caused the IO wakeup */ + if (omap_hsi_is_io_wakeup_from_hsi()) { + omap_pm_clear_dsp_wake_up(); + omap_hsi_wakeup(0); + } + omap_uart_resume_idle(); + usbhs_wakeup(); + omap_debug_uart_resume_idle(); + omap4_trigger_ioctrl(); + } + + /* Clear the interrupt */ + irqstatus_mpu &= irqenable_mpu; + omap4_prm_write_inst_reg(irqstatus_mpu, OMAP4430_PRM_OCP_SOCKET_INST, + OMAP4_PRM_IRQSTATUS_MPU_OFFSET); + + return IRQ_HANDLED; +} + +/** + * omap_default_idle() - implement a default idle for !CONFIG_CPUIDLE + * + * Implements OMAP4 memory, IO ordering requirements which can't be addressed + * with default arch_idle() hook. Used by all CPUs with !CONFIG_CPUIDLE and + * by secondary CPU with CONFIG_CPUIDLE. + */ +static void omap_default_idle(void) +{ + local_irq_disable(); + local_fiq_disable(); + + omap_do_wfi(); + + local_fiq_enable(); + local_irq_enable(); +} + +/** + * omap4_device_set_state_off() - setup device off state + * @enable: set to off or not. + * + * When Device OFF is enabled, Device is allowed to perform + * transition to off mode as soon as all power domains in MPU, IVA + * and CORE voltage are in OFF or OSWR state (open switch retention) + */ +void omap4_device_set_state_off(u8 enable) +{ +#ifdef CONFIG_OMAP_ALLOW_OSWR + if (enable) + omap4_prminst_write_inst_reg(0x1 << + OMAP4430_DEVICE_OFF_ENABLE_SHIFT, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, + OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET); + else +#endif + omap4_prminst_write_inst_reg(0x0 << + OMAP4430_DEVICE_OFF_ENABLE_SHIFT, + OMAP4430_PRM_PARTITION, OMAP4430_PRM_DEVICE_INST, + OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET); +} + +/** + * omap4_device_prev_state_off: + * returns true if the device hit OFF mode + * This is API to check whether OMAP is waking up from device OFF mode. + * There is no other status bit available for SW to read whether last state + * entered was device OFF. To work around this, CORE PD, RFF context state + * is used which is lost only when we hit device OFF state + */ +bool omap4_device_prev_state_off(void) +{ + u32 reg; + + reg = omap4_prminst_read_inst_reg(core_pwrdm->prcm_partition, + core_pwrdm->prcm_offs, + OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET) + & OMAP4430_LOSTCONTEXT_RFF_MASK; + + return reg ? true : false; +} + +void omap4_device_clear_prev_off_state(void) +{ + omap4_prminst_write_inst_reg(OMAP4430_LOSTCONTEXT_RFF_MASK | + OMAP4430_LOSTCONTEXT_DFF_MASK, + core_pwrdm->prcm_partition, + core_pwrdm->prcm_offs, + OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET); +} + +/** + * omap4_device_next_state_off: + * returns true if the device next state is OFF + * This is API to check whether OMAP is programmed for device OFF + */ +bool omap4_device_next_state_off(void) +{ + return omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, + OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET) + & OMAP4430_DEVICE_OFF_ENABLE_MASK ? true : false; +} + +static void __init omap4_pm_setup_errata(void) +{ + /* + * Current understanding is that the following errata impacts + * all OMAP4 silica + */ + if (cpu_is_omap44xx()) + pm44xx_errata |= OMAP4_PM_ERRATUM_IVA_AUTO_RET_iXXX; + /* Dynamic Dependency errata for all silicon !=443x */ + if (cpu_is_omap443x()) + pm44xx_errata |= OMAP4_PM_ERRATUM_MPU_EMIF_NO_DYNDEP_i688; + else + pm44xx_errata |= OMAP4_PM_ERRATUM_MPU_EMIF_NO_DYNDEP_IDLE_iXXX; } /** @@ -98,23 +1217,173 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) */ static int __init omap4_pm_init(void) { - int ret; + int ret = 0; + struct clockdomain *l3_1_clkdm; + struct clockdomain *ducati_clkdm, *l3_2_clkdm, *l4_per, *l4_cfg; if (!cpu_is_omap44xx()) return -ENODEV; + if (omap_rev() == OMAP4430_REV_ES1_0) { + WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); + return -ENODEV; + } + pr_err("Power Management for TI OMAP4.\n"); + /* setup the erratas */ + omap4_pm_setup_errata(); + + prcm_setup_regs(); + syscontrol_setup_regs(); + + ret = request_irq(OMAP44XX_IRQ_PRCM, + (irq_handler_t)prcm_interrupt_handler, + IRQF_NO_SUSPEND | IRQF_DISABLED, "prcm", NULL); + if (ret) { + printk(KERN_ERR "request_irq failed to register for 0x%x\n", + OMAP44XX_IRQ_PRCM); + goto err2; + } ret = pwrdm_for_each(pwrdms_setup, NULL); if (ret) { pr_err("Failed to setup powerdomains\n"); goto err2; } + /* + * On 4430: + * The dynamic dependency between MPUSS -> MEMIF and + * MPUSS -> L3_* and DUCATI -> doesn't work as expected. + * The hardware recommendation is to keep above dependencies. + * Without this system locks up or randomly crashesh. + * + * On 4460: + * The dynamic dependency between MPUSS -> MEMIF doesn't work + * as expected if MPUSS OSWR is enabled in idle. + * The dynamic dependency between MPUSS -> L4 PER & CFG + * doesn't work as expected. The hardware recommendation is + * to keep above dependencies. Without this system locks up or + * randomly crashes. + */ + mpuss_clkdm = clkdm_lookup("mpuss_clkdm"); + emif_clkdm = clkdm_lookup("l3_emif_clkdm"); + l3_1_clkdm = clkdm_lookup("l3_1_clkdm"); + l3_2_clkdm = clkdm_lookup("l3_2_clkdm"); + ducati_clkdm = clkdm_lookup("ducati_clkdm"); + l4_per = clkdm_lookup("l4_per_clkdm"); + l4_cfg = clkdm_lookup("l4_cfg_clkdm"); + if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) || + (!l3_2_clkdm) || (!ducati_clkdm) || (!l4_per) || (!l4_cfg)) + goto err2; + + /* if we cannot ever enable static dependency. */ + if (is_pm44xx_erratum(MPU_EMIF_NO_DYNDEP_i688)) + ret |= clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); + + if (cpu_is_omap443x()) { + ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm); + ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm); + ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm); + ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm); + ret |= clkdm_add_wkdep(mpuss_clkdm, l4_per); + ret |= clkdm_add_wkdep(mpuss_clkdm, l4_cfg); + ret |= clkdm_add_wkdep(ducati_clkdm, l4_per); + ret |= clkdm_add_wkdep(ducati_clkdm, l4_cfg); + if (ret) { + pr_err("Failed to add MPUSS -> L3/EMIF, DUCATI -> L3" + " and MPUSS -> L4* wakeup dependency\n"); + goto err2; + } + pr_info("OMAP4 PM: Static dependency added between" + " MPUSS <-> EMIF, MPUSS <-> L4_PER/CFG" + " MPUSS <-> L3_MAIN_1.\n"); + pr_info("OMAP4 PM: Static dependency added between" + " DUCATI <-> L4_PER/CFG and DUCATI <-> L3.\n"); + } else if (cpu_is_omap446x()) { + ret |= clkdm_add_wkdep(mpuss_clkdm, l4_per); + ret |= clkdm_add_wkdep(mpuss_clkdm, l4_cfg); + + /* There appears to be a problem between the MPUSS and L3_1 */ + ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm); + ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm); + + /* There appears to be a problem between the Ducati and L3/L4 */ + ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm); + ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm); + ret |= clkdm_add_wkdep(ducati_clkdm, l4_per); + ret |= clkdm_add_wkdep(ducati_clkdm, l4_cfg); + + if (ret) { + pr_err("Failed to add MPUSS and DUCATI -> " + "L4* and L3_1 wakeup dependency\n"); + goto err2; + } + pr_info("OMAP4 PM: Static dependency added between" + " MPUSS and DUCATI <-> L4_PER/CFG and L3_1.\n"); + } + + (void) clkdm_for_each(clkdms_setup, NULL); + + /* Get handles for VDD's for enabling/disabling SR */ + mpu_voltdm = voltdm_lookup("mpu"); + if (!mpu_voltdm) { + pr_err("%s: Failed to get voltdm for VDD MPU\n", __func__); + goto err2; + } + omap_vc_set_auto_trans(mpu_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE); + + iva_voltdm = voltdm_lookup("iva"); + if (!iva_voltdm) { + pr_err("%s: Failed to get voltdm for VDD IVA\n", __func__); + goto err2; + } + omap_vc_set_auto_trans(iva_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE); + + core_voltdm = voltdm_lookup("core"); + if (!core_voltdm) { + pr_err("%s: Failed to get voltdm for VDD CORE\n", __func__); + goto err2; + } + omap_vc_set_auto_trans(core_voltdm, + OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE); + + ret = omap4_mpuss_init(); + if (ret) { + pr_err("Failed to initialise OMAP4 MPUSS\n"); + goto err2; + } + #ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); #endif /* CONFIG_SUSPEND */ + mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); + cpu0_pwrdm = pwrdm_lookup("cpu0_pwrdm"); + core_pwrdm = pwrdm_lookup("core_pwrdm"); + per_pwrdm = pwrdm_lookup("l4per_pwrdm"); + tesla_pwrdm = pwrdm_lookup("tesla_pwrdm"); + if (!tesla_pwrdm) + pr_err("%s: Failed to lookup tesla_pwrdm\n", __func__); + + tesla_clkdm = clkdm_lookup("tesla_clkdm"); + if (!tesla_clkdm) + pr_err("%s: Failed to lookup tesla_clkdm\n", __func__); + + /* Enable wakeup for PRCM IRQ for system wide suspend */ + enable_irq_wake(OMAP44XX_IRQ_PRCM); + + /* Overwrite the default arch_idle() */ + pm_idle = omap_default_idle; + + omap4_idle_init(); + + omap_pm_is_ready_status = true; + /* let the other CPU know as well */ + smp_wmb(); + err2: return ret; } diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 9af0847..5aff165 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -19,6 +19,8 @@ #include <linux/list.h> #include <linux/errno.h> #include <linux/string.h> +#include <linux/slab.h> + #include <trace/events/power.h> #include "cm2xxx_3xxx.h" @@ -76,7 +78,7 @@ static struct powerdomain *_pwrdm_lookup(const char *name) */ static int _pwrdm_register(struct powerdomain *pwrdm) { - int i; + struct voltagedomain *voltdm; if (!pwrdm || !pwrdm->name) return -EINVAL; @@ -94,19 +96,44 @@ static int _pwrdm_register(struct powerdomain *pwrdm) if (_pwrdm_lookup(pwrdm->name)) return -EEXIST; + voltdm = voltdm_lookup(pwrdm->voltdm.name); + if (!voltdm) { + pr_err("powerdomain: %s: voltagedomain %s does not exist\n", + pwrdm->name, pwrdm->voltdm.name); + return -EINVAL; + } + pwrdm->voltdm.ptr = voltdm; + INIT_LIST_HEAD(&pwrdm->voltdm_node); + voltdm_add_pwrdm(voltdm, pwrdm); + list_add(&pwrdm->node, &pwrdm_list); - /* Initialize the powerdomain's state counter */ - for (i = 0; i < PWRDM_MAX_PWRSTS; i++) - pwrdm->state_counter[i] = 0; + /* + * Program all powerdomain target state as ON; This is to + * prevent domains from hitting low power states (if bootloader + * has target states set to something other than ON) and potentially + * even losing context while PM is not fully initilized. + * The PM late init code can then program the desired target + * state for all the power domains. + */ + pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_ON); - pwrdm->ret_logic_off_counter = 0; - for (i = 0; i < pwrdm->banks; i++) - pwrdm->ret_mem_off_counter[i] = 0; + /* Initialize the powerdomain's state counter */ + memset(&pwrdm->count, 0, sizeof(pwrdm->count)); + memset(&pwrdm->last_count, 0, sizeof(pwrdm->last_count)); + memset(&pwrdm->time, 0, sizeof(pwrdm->time)); + memset(&pwrdm->last_time, 0, sizeof(pwrdm->last_time)); pwrdm_wait_transition(pwrdm); pwrdm->state = pwrdm_read_pwrst(pwrdm); - pwrdm->state_counter[pwrdm->state] = 1; + pwrdm->count.state[pwrdm->state] = 1; + + /* Initialize priority ordered list for wakeup latency constraint */ + spin_lock_init(&pwrdm->wakeuplat_lock); + plist_head_init(&pwrdm->wakeuplat_dev_list); + + /* res_mutex protects res_list add and del ops */ + mutex_init(&pwrdm->wakeuplat_mutex); pr_debug("powerdomain: registered %s\n", pwrdm->name); @@ -119,16 +146,18 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm) u8 prev_logic_pwrst, prev_mem_pwrst; prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm); + + /* Fake logic off counter */ if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) && - (prev_logic_pwrst == PWRDM_POWER_OFF)) - pwrdm->ret_logic_off_counter++; + (pwrdm_read_logic_retst(pwrdm) == PWRDM_POWER_OFF)) + pwrdm->count.ret_logic_off++; for (i = 0; i < pwrdm->banks; i++) { prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i); if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) && (prev_mem_pwrst == PWRDM_POWER_OFF)) - pwrdm->ret_mem_off_counter[i]++; + pwrdm->count.ret_mem_off[i]++; } } @@ -149,7 +178,7 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) case PWRDM_STATE_PREV: prev = pwrdm_read_prev_pwrst(pwrdm); if (pwrdm->state != prev) - pwrdm->state_counter[prev]++; + pwrdm->count.state[prev]++; if (prev == PWRDM_POWER_RET) _update_logic_membank_counters(pwrdm); /* @@ -169,7 +198,7 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) } if (state != prev) - pwrdm->state_counter[state]++; + pwrdm->count.state[state]++; pm_dbg_update_time(pwrdm, prev); @@ -196,7 +225,7 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) /** * pwrdm_init - set up the powerdomain layer * @pwrdm_list: array of struct powerdomain pointers to register - * @custom_funcs: func pointers for arch specific implementations + * @custom_funcs: func pointers for arch specfic implementations * * Loop through the array of powerdomains @pwrdm_list, registering all * that are available on the current CPU. If pwrdm_list is supplied @@ -208,6 +237,7 @@ void pwrdm_init(struct powerdomain **pwrdm_list, struct pwrdm_ops *custom_funcs) { struct powerdomain **p = NULL; + if (!custom_funcs) WARN(1, "powerdomain: No custom pwrdm functions registered\n"); else @@ -383,6 +413,18 @@ int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, } /** + * pwrdm_get_voltdm - return a ptr to the voltdm that this pwrdm resides in + * @pwrdm: struct powerdomain * + * + * Return a pointer to the struct voltageomain that the specified powerdomain + * @pwrdm exists in. + */ +struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm) +{ + return pwrdm->voltdm.ptr; +} + +/** * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain * @pwrdm: struct powerdomain * * @@ -935,25 +977,31 @@ int pwrdm_post_transition(void) * @pwrdm: struct powerdomain * to wait for * * Context loss count is the sum of powerdomain off-mode counter, the - * logic off counter and the per-bank memory off counter. Returns 0 + * logic off counter and the per-bank memory off counter. Returns negative * (and WARNs) upon error, otherwise, returns the context loss count. */ -u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm) +int pwrdm_get_context_loss_count(struct powerdomain *pwrdm) { int i, count; if (!pwrdm) { WARN(1, "powerdomain: %s: pwrdm is null\n", __func__); - return 0; + return -ENODEV; } - count = pwrdm->state_counter[PWRDM_POWER_OFF]; - count += pwrdm->ret_logic_off_counter; + count = pwrdm->count.state[PWRDM_POWER_OFF]; + count += pwrdm->count.ret_logic_off; for (i = 0; i < pwrdm->banks; i++) - count += pwrdm->ret_mem_off_counter[i]; + count += pwrdm->count.ret_mem_off[i]; - pr_debug("powerdomain: %s: context loss count = %u\n", + /* + * Context loss count has to be a non-negative value. Clear the sign + * bit to get a value range from 0 to INT_MAX. + */ + count &= INT_MAX; + + pr_debug("powerdomain: %s: context loss count = %d\n", pwrdm->name, count); return count; @@ -999,3 +1047,163 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm) return 0; } + + +/** + * pwrdm_wakeuplat_set_constraint - Set powerdomain wakeup latency constraint + * @pwrdm: struct powerdomain * to which requesting device belongs to + * @dev: struct device * of requesting device + * @t: wakeup latency constraint in microseconds + * + * Adds new entry to powerdomain's wakeup latency constraint list. + * If the requesting device already exists in the list, old value is + * overwritten. Checks whether current power state is still adequate. + * Returns -EINVAL if the powerdomain or device pointer is NULL, + * or -ENOMEM if kmalloc fails, or -ERANGE if constraint can't be met, + * or returns 0 upon success. + */ +int pwrdm_wakeuplat_set_constraint (struct powerdomain *pwrdm, + struct device *dev, unsigned long t) +{ + struct wakeuplat_dev_list *user; + int found = 0, ret = 0; + + if (!pwrdm || !dev) { + WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); + return -EINVAL; + } + + mutex_lock(&pwrdm->wakeuplat_mutex); + + plist_for_each_entry(user, &pwrdm->wakeuplat_dev_list, node) { + if (user->dev == dev) { + found = 1; + break; + } + } + + /* Add new entry to the list or update existing request */ + if (found && user->constraint_us == t) { + goto exit_set; + } else if (!found) { + user = kzalloc(sizeof(struct wakeuplat_dev_list), GFP_KERNEL); + if (!user) { + pr_err("OMAP PM: FATAL ERROR: kzalloc failed\n"); + ret = -ENOMEM; + goto exit_set; + } + user->dev = dev; + } else { + plist_del(&user->node, &pwrdm->wakeuplat_dev_list); + } + + plist_node_init(&user->node, t); + spin_lock(&pwrdm->wakeuplat_lock); + plist_add(&user->node, &pwrdm->wakeuplat_dev_list); + spin_unlock(&pwrdm->wakeuplat_lock); + user->node.prio = user->constraint_us = t; + + ret = pwrdm_wakeuplat_update_pwrst(pwrdm); + +exit_set: + mutex_unlock(&pwrdm->wakeuplat_mutex); + + return ret; +} + +/** + * pwrdm_wakeuplat_release_constraint - Release powerdomain wkuplat constraint + * @pwrdm: struct powerdomain * to which requesting device belongs to + * @dev: struct device * of requesting device + * + * Removes device's entry from powerdomain's wakeup latency constraint list. + * Checks whether current power state is still adequate. + * Returns -EINVAL if the powerdomain or device pointer is NULL or + * no such entry exists in the list, or returns 0 upon success. + */ +int pwrdm_wakeuplat_release_constraint (struct powerdomain *pwrdm, + struct device *dev) +{ + struct wakeuplat_dev_list *user; + int found = 0, ret = 0; + + if (!pwrdm || !dev) { + WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__); + return -EINVAL; + } + + mutex_lock(&pwrdm->wakeuplat_mutex); + + plist_for_each_entry(user, &pwrdm->wakeuplat_dev_list, node) { + if (user->dev == dev) { + found = 1; + break; + } + } + + if (!found) { + pr_err("OMAP PM: Error: no prior constraint to release\n"); + ret = -EINVAL; + goto exit_rls; + } + + spin_lock(&pwrdm->wakeuplat_lock); + plist_del(&user->node, &pwrdm->wakeuplat_dev_list); + spin_unlock(&pwrdm->wakeuplat_lock); + kfree(user); + + ret = pwrdm_wakeuplat_update_pwrst(pwrdm); + +exit_rls: + mutex_unlock(&pwrdm->wakeuplat_mutex); + + return ret; +} + +/** + * pwrdm_wakeuplat_update_pwrst - Update power domain power state if needed + * @pwrdm: struct powerdomain * to which requesting device belongs to + * + * Finds minimum latency value from all entries in the list and + * the power domain power state neeting the constraint. Programs + * new state if it is different from next power state. + * Returns -EINVAL if the powerdomain or device pointer is NULL or + * no such entry exists in the list, or -ERANGE if constraint can't be met, + * or returns 0 upon success. + */ +int pwrdm_wakeuplat_update_pwrst(struct powerdomain *pwrdm) +{ + struct plist_node *node; + int ret = 0, new_state; + unsigned long min_latency = -1; + + if (!plist_head_empty(&pwrdm->wakeuplat_dev_list)) { + node = plist_last(&pwrdm->wakeuplat_dev_list); + min_latency = node->prio; + } + + /* Find power state with wakeup latency < minimum constraint. */ + for (new_state = 0x0; new_state < PWRDM_MAX_PWRSTS; new_state++) { + if (min_latency == -1 || + pwrdm->wakeup_lat[new_state] < min_latency) + break; + } + + /* No power state wkuplat met constraint. Keep power domain ON. */ + if (new_state == PWRDM_MAX_PWRSTS) { + new_state = PWRDM_FUNC_PWRST_ON; + ret = -ERANGE; + } + + if (pwrdm_read_next_pwrst(pwrdm) != new_state) { + if (cpu_is_omap44xx() || cpu_is_omap34xx()) + omap_set_pwrdm_state(pwrdm, new_state); + } + + pr_debug("OMAP PM: %s pwrst: curr= %d, prev= %d next= %d " + "wkuplat_min= %lu, state= %d\n", pwrdm->name, + pwrdm_read_pwrst(pwrdm), pwrdm_read_prev_pwrst(pwrdm), + pwrdm_read_next_pwrst(pwrdm), min_latency, new_state); + + return ret; +} diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index d23d979..59aef2b 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -19,11 +19,16 @@ #include <linux/types.h> #include <linux/list.h> +#include <linux/plist.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> #include <linux/atomic.h> #include <plat/cpu.h> +#include "voltage.h" + /* Powerdomain basic power states */ #define PWRDM_POWER_OFF 0x0 #define PWRDM_POWER_RET 0x1 @@ -43,6 +48,18 @@ #define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON) #define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON) +#define PWRSTS_RET_INA_ON ((1 << PWRDM_POWER_RET) | \ + (1 << PWRDM_POWER_INACTIVE) | \ + (1 << PWRDM_POWER_ON)) + +#define PWRSTS_OFF_INA_ON ((1 << PWRDM_POWER_OFF) | \ + (1 << PWRDM_POWER_INACTIVE) | \ + (1 << PWRDM_POWER_ON)) + +#define PWRSTS_OFF_RET_INA_ON ((1 << PWRDM_POWER_OFF) | \ + (1 << PWRDM_POWER_RET) | \ + (1 << PWRDM_POWER_INACTIVE) | \ + (1 << PWRDM_POWER_ON)) /* Powerdomain flags */ #define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */ @@ -72,12 +89,33 @@ /* XXX A completely arbitrary number. What is reasonable here? */ #define PWRDM_TRANSITION_BAILOUT 100000 +/* Powerdomain functional power states */ +#define PWRDM_FUNC_PWRST_OFF 0x0 +#define PWRDM_FUNC_PWRST_OSWR 0x1 +#define PWRDM_FUNC_PWRST_CSWR 0x2 +#define PWRDM_FUNC_PWRST_ON 0x3 + +#define PWRDM_MAX_FUNC_PWRSTS 4 + +#define UNSUP_STATE -1 + struct clockdomain; struct powerdomain; +struct powerdomain_count_stats { + unsigned state[PWRDM_MAX_PWRSTS]; + unsigned ret_logic_off; + unsigned ret_mem_off[PWRDM_MAX_MEM_BANKS]; +}; + +struct powerdomain_time_stats { + s64 state[PWRDM_MAX_PWRSTS]; +}; + /** * struct powerdomain - OMAP powerdomain * @name: Powerdomain name + * @voltdm: voltagedomain containing this powerdomain * @omap_chip: represents the OMAP chip types containing this pwrdm * @prcm_offs: the address offset from CM_BASE/PRM_BASE * @prcm_partition: (OMAP4 only) the PRCM partition ID containing @prcm_offs @@ -89,15 +127,22 @@ struct powerdomain; * @pwrsts_mem_on: Possible memory bank pwrstates when pwrdm in ON * @pwrdm_clkdms: Clockdomains in this powerdomain * @node: list_head linking all powerdomains + * @voltdm_node: list_head linking all powerdomains in a voltagedomain * @state: * @state_counter: * @timer: * @state_timer: - * - * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. + * @wakeup_lat: Wakeup latencies for possible powerdomain power states + * @wakeuplat_lock: spinlock for plist + * @wakeuplat_dev_list: plist_head linking all devices placing constraint + * @wa * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. */ struct powerdomain { const char *name; + union { + const char *name; + struct voltagedomain *ptr; + } voltdm; const struct omap_chip_id omap_chip; const s16 prcm_offs; const u8 pwrsts; @@ -109,15 +154,27 @@ struct powerdomain { const u8 prcm_partition; struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS]; struct list_head node; + struct list_head voltdm_node; int state; - unsigned state_counter[PWRDM_MAX_PWRSTS]; - unsigned ret_logic_off_counter; - unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; + + struct powerdomain_count_stats count; + struct powerdomain_count_stats last_count; #ifdef CONFIG_PM_DEBUG s64 timer; - s64 state_timer[PWRDM_MAX_PWRSTS]; + struct powerdomain_time_stats time; + struct powerdomain_time_stats last_time; #endif + const u32 wakeup_lat[PWRDM_MAX_FUNC_PWRSTS]; + spinlock_t wakeuplat_lock; + struct plist_head wakeuplat_dev_list; + struct mutex wakeuplat_mutex; +}; + +struct wakeuplat_dev_list { + struct device *dev; + unsigned long constraint_us; + struct plist_node node; }; /** @@ -176,6 +233,7 @@ int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm); int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, int (*fn)(struct powerdomain *pwrdm, struct clockdomain *clkdm)); +struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm); int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm); @@ -207,7 +265,7 @@ int pwrdm_clkdm_state_switch(struct clockdomain *clkdm); int pwrdm_pre_transition(void); int pwrdm_post_transition(void); int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); -u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm); +int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); extern void omap2xxx_powerdomains_init(void); @@ -226,5 +284,10 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank); extern struct powerdomain wkup_omap2_pwrdm; extern struct powerdomain gfx_omap2_pwrdm; +int pwrdm_wakeuplat_set_constraint(struct powerdomain *pwrdm, + struct device *dev, unsigned long t); +int pwrdm_wakeuplat_release_constraint(struct powerdomain *pwrdm, + struct device *dev); +int pwrdm_wakeuplat_update_pwrst(struct powerdomain *pwrdm); #endif diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c index a7880af..c0aab2a 100644 --- a/arch/arm/mach-omap2/powerdomain44xx.c +++ b/arch/arm/mach-omap2/powerdomain44xx.c @@ -19,9 +19,13 @@ #include "powerdomain.h" #include <plat/prcm.h> #include "prm2xxx_3xxx.h" +#include "cminst44xx.h" #include "prm44xx.h" +#include "prcm44xx.h" #include "prminst44xx.h" #include "prm-regbits-44xx.h" +#include "cm-regbits-44xx.h" +#include "cm2_44xx.h" static int omap4_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) { @@ -207,6 +211,41 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) return 0; } +static int omap4_pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm) +{ + /* + * FIXME: This should be fixed right way by moving it into HWMOD + * or clock framework since sar control is moved to module level + */ + omap4_cminst_rmw_inst_reg_bits(OMAP4430_SAR_MODE_MASK, + 1 << OMAP4430_SAR_MODE_SHIFT, OMAP4430_CM2_PARTITION, + OMAP4430_CM2_L3INIT_INST, + OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET); + omap4_cminst_rmw_inst_reg_bits(OMAP4430_SAR_MODE_MASK, + 1 << OMAP4430_SAR_MODE_SHIFT, OMAP4430_CM2_PARTITION, + OMAP4430_CM2_L3INIT_INST, + OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET); + return 0; +} + +static int omap4_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm) +{ + /* + * FIXME: This should be fixed right way by moving it into HWMOD + * or clock framework since sar control is moved to module level + */ + omap4_cminst_rmw_inst_reg_bits(OMAP4430_SAR_MODE_MASK, + 0 << OMAP4430_SAR_MODE_SHIFT, OMAP4430_CM2_PARTITION, + OMAP4430_CM2_L3INIT_INST, + OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET); + omap4_cminst_rmw_inst_reg_bits(OMAP4430_SAR_MODE_MASK, + 0 << OMAP4430_SAR_MODE_SHIFT, OMAP4430_CM2_PARTITION, + OMAP4430_CM2_L3INIT_INST, + OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET); + + return 0; +} + struct pwrdm_ops omap4_pwrdm_operations = { .pwrdm_set_next_pwrst = omap4_pwrdm_set_next_pwrst, .pwrdm_read_next_pwrst = omap4_pwrdm_read_next_pwrst, @@ -222,4 +261,6 @@ struct pwrdm_ops omap4_pwrdm_operations = { .pwrdm_set_mem_onst = omap4_pwrdm_set_mem_onst, .pwrdm_set_mem_retst = omap4_pwrdm_set_mem_retst, .pwrdm_wait_transition = omap4_pwrdm_wait_transition, + .pwrdm_enable_hdwr_sar = omap4_pwrdm_enable_hdwr_sar, + .pwrdm_disable_hdwr_sar = omap4_pwrdm_disable_hdwr_sar, }; diff --git a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c index 4210c33..2242c8e 100644 --- a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c @@ -70,6 +70,7 @@ struct powerdomain gfx_omap2_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, + .voltdm = { .name = "core" }, }; struct powerdomain wkup_omap2_pwrdm = { @@ -77,4 +78,5 @@ struct powerdomain wkup_omap2_pwrdm = { .prcm_offs = WKUP_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430), .pwrsts = PWRSTS_ON, + .voltdm = { .name = "wakeup" }, }; diff --git a/arch/arm/mach-omap2/powerdomains2xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_data.c index cc389fb..274f64c 100644 --- a/arch/arm/mach-omap2/powerdomains2xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains2xxx_data.c @@ -38,6 +38,7 @@ static struct powerdomain dsp_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, }, + .voltdm = { .name = "core" }, }; static struct powerdomain mpu_24xx_pwrdm = { @@ -53,6 +54,7 @@ static struct powerdomain mpu_24xx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, }, + .voltdm = { .name = "core" }, }; static struct powerdomain core_24xx_pwrdm = { @@ -71,6 +73,7 @@ static struct powerdomain core_24xx_pwrdm = { [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */ }, + .voltdm = { .name = "core" }, }; @@ -95,6 +98,7 @@ static struct powerdomain mdm_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, + .voltdm = { .name = "core" }, }; #endif /* CONFIG_SOC_OMAP2430 */ diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c index 469a920..b91224b 100644 --- a/arch/arm/mach-omap2/powerdomains3xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c @@ -52,6 +52,13 @@ static struct powerdomain iva2_pwrdm = { [2] = PWRSTS_OFF_ON, [3] = PWRSTS_ON, }, + .voltdm = { .name = "mpu_iva" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1100, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 350, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; static struct powerdomain mpu_3xxx_pwrdm = { @@ -68,6 +75,13 @@ static struct powerdomain mpu_3xxx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_OFF_ON, }, + .voltdm = { .name = "mpu_iva" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 95, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 45, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* @@ -98,6 +112,13 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = { [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ }, + .voltdm = { .name = "core" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 100, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 60, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; static struct powerdomain core_3xxx_es3_1_pwrdm = { @@ -121,6 +142,13 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = { [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ }, + .voltdm = { .name = "core" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 100, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 60, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; static struct powerdomain dss_pwrdm = { @@ -136,6 +164,13 @@ static struct powerdomain dss_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, + .voltdm = { .name = "core" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 70, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 20, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* @@ -157,6 +192,13 @@ static struct powerdomain sgx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, + .voltdm = { .name = "core" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; static struct powerdomain cam_pwrdm = { @@ -172,6 +214,13 @@ static struct powerdomain cam_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, + .voltdm = { .name = "core" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 850, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 35, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; static struct powerdomain per_pwrdm = { @@ -187,12 +236,20 @@ static struct powerdomain per_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, + .voltdm = { .name = "core" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 200, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 110, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; static struct powerdomain emu_pwrdm = { .name = "emu_pwrdm", .prcm_offs = OMAP3430_EMU_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .voltdm = { .name = "core" }, }; static struct powerdomain neon_pwrdm = { @@ -201,6 +258,13 @@ static struct powerdomain neon_pwrdm = { .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_RET, + .voltdm = { .name = "mpu_iva" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 200, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 35, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; static struct powerdomain usbhost_pwrdm = { @@ -223,36 +287,48 @@ static struct powerdomain usbhost_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* MEMONSTATE */ }, + .voltdm = { .name = "core" }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 800, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 150, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; static struct powerdomain dpll1_pwrdm = { .name = "dpll1_pwrdm", .prcm_offs = MPU_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain dpll2_pwrdm = { .name = "dpll2_pwrdm", .prcm_offs = OMAP3430_IVA2_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .voltdm = { .name = "mpu_iva" }, }; static struct powerdomain dpll3_pwrdm = { .name = "dpll3_pwrdm", .prcm_offs = PLL_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .voltdm = { .name = "core" }, }; static struct powerdomain dpll4_pwrdm = { .name = "dpll4_pwrdm", .prcm_offs = PLL_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .voltdm = { .name = "core" }, }; static struct powerdomain dpll5_pwrdm = { .name = "dpll5_pwrdm", .prcm_offs = PLL_MOD, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .voltdm = { .name = "core" }, }; /* As powerdomains are added or removed above, this list must also be changed */ diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c index c4222c7..d645d68 100644 --- a/arch/arm/mach-omap2/powerdomains44xx_data.c +++ b/arch/arm/mach-omap2/powerdomains44xx_data.c @@ -1,7 +1,7 @@ /* * OMAP4 Power domains framework * - * Copyright (C) 2009-2010 Texas Instruments, Inc. + * Copyright (C) 2009-2011 Texas Instruments, Inc. * Copyright (C) 2009-2011 Nokia Corporation * * Abhijit Pagare (abhijitpagare@ti.com) @@ -33,10 +33,11 @@ /* core_44xx_pwrdm: CORE power domain */ static struct powerdomain core_44xx_pwrdm = { .name = "core_pwrdm", + .voltdm = { .name = "core" }, .prcm_offs = OMAP4430_PRM_CORE_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_RET_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 5, .pwrsts_mem_ret = { @@ -54,15 +55,22 @@ static struct powerdomain core_44xx_pwrdm = { [4] = PWRSTS_ON, /* ducati_unicache */ }, .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* gfx_44xx_pwrdm: 3D accelerator power domain */ static struct powerdomain gfx_44xx_pwrdm = { .name = "gfx_pwrdm", + .voltdm = { .name = "core" }, .prcm_offs = OMAP4430_PRM_GFX_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_INA_ON, .banks = 1, .pwrsts_mem_ret = { [0] = PWRSTS_OFF, /* gfx_mem */ @@ -71,16 +79,22 @@ static struct powerdomain gfx_44xx_pwrdm = { [0] = PWRSTS_ON, /* gfx_mem */ }, .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* abe_44xx_pwrdm: Audio back end power domain */ static struct powerdomain abe_44xx_pwrdm = { .name = "abe_pwrdm", + .voltdm = { .name = "iva" }, .prcm_offs = OMAP4430_PRM_ABE_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_RET_ON, - .pwrsts_logic_ret = PWRSTS_OFF, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_RET_INA_ON, .banks = 2, .pwrsts_mem_ret = { [0] = PWRSTS_RET, /* aessmem */ @@ -91,16 +105,22 @@ static struct powerdomain abe_44xx_pwrdm = { [1] = PWRSTS_ON, /* periphmem */ }, .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* dss_44xx_pwrdm: Display subsystem power domain */ static struct powerdomain dss_44xx_pwrdm = { .name = "dss_pwrdm", + .voltdm = { .name = "core" }, .prcm_offs = OMAP4430_PRM_DSS_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_RET_ON, - .pwrsts_logic_ret = PWRSTS_OFF, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_RET_INA_ON, .banks = 1, .pwrsts_mem_ret = { [0] = PWRSTS_OFF, /* dss_mem */ @@ -109,15 +129,22 @@ static struct powerdomain dss_44xx_pwrdm = { [0] = PWRSTS_ON, /* dss_mem */ }, .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* tesla_44xx_pwrdm: Tesla processor power domain */ static struct powerdomain tesla_44xx_pwrdm = { .name = "tesla_pwrdm", + .voltdm = { .name = "iva" }, .prcm_offs = OMAP4430_PRM_TESLA_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_RET_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 3, .pwrsts_mem_ret = { @@ -131,14 +158,21 @@ static struct powerdomain tesla_44xx_pwrdm = { [2] = PWRSTS_ON, /* tesla_l2 */ }, .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* wkup_44xx_pwrdm: Wake-up power domain */ static struct powerdomain wkup_44xx_pwrdm = { .name = "wkup_pwrdm", + .voltdm = { .name = "wakeup" }, .prcm_offs = OMAP4430_PRM_WKUP_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), .pwrsts = PWRSTS_ON, .banks = 1, .pwrsts_mem_ret = { @@ -152,10 +186,11 @@ static struct powerdomain wkup_44xx_pwrdm = { /* cpu0_44xx_pwrdm: MPU0 processor and Neon coprocessor power domain */ static struct powerdomain cpu0_44xx_pwrdm = { .name = "cpu0_pwrdm", + .voltdm = { .name = "mpu" }, .prcm_offs = OMAP4430_PRCM_MPU_CPU0_INST, .prcm_partition = OMAP4430_PRCM_MPU_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_RET_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 1, .pwrsts_mem_ret = { @@ -164,15 +199,22 @@ static struct powerdomain cpu0_44xx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* cpu0_l1 */ }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */ static struct powerdomain cpu1_44xx_pwrdm = { .name = "cpu1_pwrdm", + .voltdm = { .name = "mpu" }, .prcm_offs = OMAP4430_PRCM_MPU_CPU1_INST, .prcm_partition = OMAP4430_PRCM_MPU_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_RET_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 1, .pwrsts_mem_ret = { @@ -181,15 +223,21 @@ static struct powerdomain cpu1_44xx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* cpu1_l1 */ }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* emu_44xx_pwrdm: Emulation power domain */ static struct powerdomain emu_44xx_pwrdm = { .name = "emu_pwrdm", + .voltdm = { .name = "wakeup" }, .prcm_offs = OMAP4430_PRM_EMU_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), .banks = 1, .pwrsts_mem_ret = { [0] = PWRSTS_OFF, /* emu_bank */ @@ -200,12 +248,13 @@ static struct powerdomain emu_44xx_pwrdm = { }; /* mpu_44xx_pwrdm: Modena processor and the Neon coprocessor power domain */ -static struct powerdomain mpu_44xx_pwrdm = { +static struct powerdomain mpu_443x_pwrdm = { .name = "mpu_pwrdm", + .voltdm = { .name = "mpu" }, .prcm_offs = OMAP4430_PRM_MPU_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_RET_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP443X), + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 3, .pwrsts_mem_ret = { @@ -218,16 +267,47 @@ static struct powerdomain mpu_44xx_pwrdm = { [1] = PWRSTS_ON, /* mpu_l2 */ [2] = PWRSTS_ON, /* mpu_ram */ }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, +}; + +static struct powerdomain mpu_446x_pwrdm = { + .name = "mpu_pwrdm", + .voltdm = { .name = "mpu" }, + .prcm_offs = OMAP4430_PRM_MPU_INST, + .prcm_partition = OMAP4430_PRM_PARTITION, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP446X), + .pwrsts = PWRSTS_RET_INA_ON, + .pwrsts_logic_ret = PWRSTS_OFF_RET, + .banks = 2, + .pwrsts_mem_ret = { + [0] = PWRSTS_OFF_RET, /* mpu_l2 */ + [1] = PWRSTS_RET, /* mpu_ram */ + }, + .pwrsts_mem_on = { + [0] = PWRSTS_ON, /* mpu_l2 */ + [1] = PWRSTS_ON, /* mpu_ram */ + }, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* ivahd_44xx_pwrdm: IVA-HD power domain */ static struct powerdomain ivahd_44xx_pwrdm = { .name = "ivahd_pwrdm", + .voltdm = { .name = "iva" }, .prcm_offs = OMAP4430_PRM_IVAHD_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_RET_ON, - .pwrsts_logic_ret = PWRSTS_OFF, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_RET_INA_ON, .banks = 4, .pwrsts_mem_ret = { [0] = PWRSTS_OFF, /* hwa_mem */ @@ -242,15 +322,22 @@ static struct powerdomain ivahd_44xx_pwrdm = { [3] = PWRSTS_ON, /* tcm2_mem */ }, .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* cam_44xx_pwrdm: Camera subsystem power domain */ static struct powerdomain cam_44xx_pwrdm = { .name = "cam_pwrdm", + .voltdm = { .name = "core" }, .prcm_offs = OMAP4430_PRM_CAM_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_INA_ON, .banks = 1, .pwrsts_mem_ret = { [0] = PWRSTS_OFF, /* cam_mem */ @@ -259,15 +346,22 @@ static struct powerdomain cam_44xx_pwrdm = { [0] = PWRSTS_ON, /* cam_mem */ }, .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_CSWR] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* l3init_44xx_pwrdm: L3 initators pheripherals power domain */ static struct powerdomain l3init_44xx_pwrdm = { .name = "l3init_pwrdm", + .voltdm = { .name = "core" }, .prcm_offs = OMAP4430_PRM_L3INIT_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_RET_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 1, .pwrsts_mem_ret = { @@ -276,16 +370,23 @@ static struct powerdomain l3init_44xx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* l3init_bank1 */ }, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = PWRDM_HAS_LOWPOWERSTATECHANGE | PWRDM_HAS_HDWR_SAR, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = 1000, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* l4per_44xx_pwrdm: Target peripherals power domain */ static struct powerdomain l4per_44xx_pwrdm = { .name = "l4per_pwrdm", + .voltdm = { .name = "core" }, .prcm_offs = OMAP4430_PRM_L4PER_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_RET_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks = 2, .pwrsts_mem_ret = { @@ -297,6 +398,12 @@ static struct powerdomain l4per_44xx_pwrdm = { [1] = PWRSTS_ON, /* retained_bank */ }, .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .wakeup_lat = { + [PWRDM_FUNC_PWRST_OFF] = UNSUP_STATE, + [PWRDM_FUNC_PWRST_OSWR] = 600, + [PWRDM_FUNC_PWRST_CSWR] = 300, + [PWRDM_FUNC_PWRST_ON] = 0, + }, }; /* @@ -305,19 +412,21 @@ static struct powerdomain l4per_44xx_pwrdm = { */ static struct powerdomain always_on_core_44xx_pwrdm = { .name = "always_on_core_pwrdm", + .voltdm = { .name = "core" }, .prcm_offs = OMAP4430_PRM_ALWAYS_ON_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), .pwrsts = PWRSTS_ON, }; /* cefuse_44xx_pwrdm: Customer efuse controller power domain */ static struct powerdomain cefuse_44xx_pwrdm = { .name = "cefuse_pwrdm", + .voltdm = { .name = "core" }, .prcm_offs = OMAP4430_PRM_CEFUSE_INST, .prcm_partition = OMAP4430_PRM_PARTITION, - .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430), - .pwrsts = PWRSTS_OFF_ON, + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX), + .pwrsts = PWRSTS_OFF_INA_ON, }; /* @@ -339,7 +448,8 @@ static struct powerdomain *powerdomains_omap44xx[] __initdata = { &cpu0_44xx_pwrdm, &cpu1_44xx_pwrdm, &emu_44xx_pwrdm, - &mpu_44xx_pwrdm, + &mpu_443x_pwrdm, + &mpu_446x_pwrdm, &ivahd_44xx_pwrdm, &cam_44xx_pwrdm, &l3init_44xx_pwrdm, diff --git a/arch/arm/mach-omap2/prcm-debug.c b/arch/arm/mach-omap2/prcm-debug.c new file mode 100644 index 0000000..bbc6743 --- /dev/null +++ b/arch/arm/mach-omap2/prcm-debug.c @@ -0,0 +1,1688 @@ +/* + * OMAP4 PRCM Debugging + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/io.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#include "prcm-debug.h" +#include "prm-regbits-44xx.h" +#include "prcm44xx.h" +#include "prm44xx.h" +#include "prminst44xx.h" +#include "cm44xx.h" +#include "cm1_44xx.h" +#include "cm2_44xx.h" +#include "cm-regbits-44xx.h" +#include "cminst44xx.h" +#include "prcm_mpu44xx.h" +#include "powerdomain.h" + +/* DPLLs */ + +struct d_dpll_info { + char *name; + void *idlestreg; + struct d_dpll_derived *derived[]; +}; + +struct d_dpll_derived { + char *name; + void *gatereg; + u32 gatemask; +}; + +static struct d_dpll_derived derived_dpll_per_m2 = { + .name = "DPLL_PER_M2", + .gatereg = OMAP4430_CM_DIV_M2_DPLL_PER, + .gatemask = 0xa00, +}; + +static struct d_dpll_derived derived_dpll_per_m3 = { + .name = "DPLL_PER_M3", + .gatereg = OMAP4430_CM_DIV_M3_DPLL_PER, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_per_m4 = { + .name = "DPLL_PER_M4", + .gatereg = OMAP4430_CM_DIV_M4_DPLL_PER, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_per_m5 = { + .name = "DPLL_PER_M5", + .gatereg = OMAP4430_CM_DIV_M5_DPLL_PER, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_per_m6 = { + .name = "DPLL_PER_M6", + .gatereg = OMAP4430_CM_DIV_M6_DPLL_PER, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_per_m7 = { + .name = "DPLL_PER_M7", + .gatereg = OMAP4430_CM_DIV_M7_DPLL_PER, + .gatemask = 0x200, +}; + + +static struct d_dpll_info dpll_per = { + .name = "DPLL_PER", + .idlestreg = OMAP4430_CM_IDLEST_DPLL_PER, + .derived = {&derived_dpll_per_m2, &derived_dpll_per_m3, + &derived_dpll_per_m4, &derived_dpll_per_m5, + &derived_dpll_per_m6, &derived_dpll_per_m7, + NULL}, +}; + +static struct d_dpll_derived derived_dpll_core_m2 = { + .name = "DPLL_CORE_M2", + .gatereg = OMAP4430_CM_DIV_M2_DPLL_CORE, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_core_m3 = { + .name = "DPLL_CORE_M3", + .gatereg = OMAP4430_CM_DIV_M3_DPLL_CORE, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_core_m4 = { + .name = "DPLL_CORE_M4", + .gatereg = OMAP4430_CM_DIV_M4_DPLL_CORE, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_core_m5 = { + .name = "DPLL_CORE_M5", + .gatereg = OMAP4430_CM_DIV_M5_DPLL_CORE, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_core_m6 = { + .name = "DPLL_CORE_M6", + .gatereg = OMAP4430_CM_DIV_M6_DPLL_CORE, + .gatemask = 0x200, +}; + +static struct d_dpll_derived derived_dpll_core_m7 = { + .name = "DPLL_CORE_M7", + .gatereg = OMAP4430_CM_DIV_M7_DPLL_CORE, + .gatemask = 0x200, +}; + +static struct d_dpll_info dpll_core = { + .name = "DPLL_CORE", + .idlestreg = OMAP4430_CM_IDLEST_DPLL_CORE, + .derived = {&derived_dpll_core_m2, &derived_dpll_core_m3, + &derived_dpll_core_m4, &derived_dpll_core_m5, + &derived_dpll_core_m6, &derived_dpll_core_m7, + NULL}, +}; + +static struct d_dpll_info dpll_abe = { + .name = "DPLL_ABE", + .idlestreg = OMAP4430_CM_IDLEST_DPLL_ABE, + .derived = {/* &derived_dpll_abe_m2, &derived_dpll_abe_m3, + &derived_dpll_abe_m4, &derived_dpll_abe_m5, + &derived_dpll_abe_m6, &derived_dpll_abe_m7, + */ NULL}, +}; + +static struct d_dpll_info dpll_mpu = { + .name = "DPLL_MPU", + .idlestreg = OMAP4430_CM_IDLEST_DPLL_MPU, + .derived = {/* &derived_dpll_mpu_m2, */ NULL}, +}; + +static struct d_dpll_info dpll_iva = { + .name = "DPLL_IVA", + .idlestreg = OMAP4430_CM_IDLEST_DPLL_IVA, + .derived = {/* &derived_dpll_iva_m4, &derived_dpll_iva_m5, */ NULL}, +}; + +static struct d_dpll_info dpll_usb = { + .name = "DPLL_USB", + .idlestreg = OMAP4430_CM_IDLEST_DPLL_USB, + .derived = {/* &derived_dpll_usb_m2, */ NULL}, +}; + + +/* Other internal generators */ + +struct d_intgen_info { + char *name; + void *gatereg; + u32 gatemask; +}; + +static struct d_intgen_info intgen_cm1_abe = { + .name = "CM1_ABE", + .gatereg = OMAP4430_CM_CLKSEL_ABE, + .gatemask = 0x500, +}; + + + +/* Modules */ + +#define MOD_MASTER (1 << 0) +#define MOD_SLAVE (1 << 1) +#define MOD_MODE (1 << 2) + +struct d_mod_info { + char *name; + void *clkctrl; + int flags; + int optclk; +}; + +static struct d_mod_info mod_debug = { + .name = "DEBUG", + .clkctrl = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_bandgap = { + .name = "BANDGAP", + .clkctrl = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL, + .flags = 0, + .optclk = 0x100, +}; + +static struct d_mod_info mod_gpio1 = { + .name = "GPIO1", + .clkctrl = OMAP4430_CM_WKUP_GPIO1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x100, +}; + +static struct d_mod_info mod_keyboard = { + .name = "KEYBOARD", + .clkctrl = OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_sar_ram = { + .name = "SAR_RAM", + .clkctrl = OMAP4430_CM_WKUP_SARRAM_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_32ktimer = { + .name = "32KTIMER", + .clkctrl = OMAP4430_CM_WKUP_SYNCTIMER_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_gptimer1 = { + .name = "GPTIMER1", + .clkctrl = OMAP4430_CM_WKUP_TIMER1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_wdtimer2 = { + .name = "WDTIMER2", + .clkctrl = OMAP4430_CM_WKUP_WDT2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_l4_wkup = { + .name = "L4_WKUP", + .clkctrl = OMAP4430_CM_WKUP_L4WKUP_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_sr_core = { + .name = "SR_CORE", + .clkctrl = OMAP4430_CM_ALWON_SR_CORE_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_sr_iva = { + .name = "SR_IVA", + .clkctrl = OMAP4430_CM_ALWON_SR_IVA_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_sr_mpu = { + .name = "SR_MPU", + .clkctrl = OMAP4430_CM_ALWON_SR_MPU_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_fdif = { + .name = "FACE DETECT", + .clkctrl = OMAP4430_CM_CAM_FDIF_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER| MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_iss = { + .name = "ISS", + .clkctrl = OMAP4430_CM_CAM_ISS_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER| MOD_SLAVE, + .optclk = 0x100, +}; + +static struct d_mod_info mod_spinlock = { + .name = "SPINLOCK", + .clkctrl = OMAP4430_CM_L4CFG_HW_SEM_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_l4_cfg_interconnect = { + .name = "L4_CFG interconnect", + .clkctrl = OMAP4430_CM_L4CFG_L4_CFG_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_mailbox = { + .name = "MAILBOX", + .clkctrl = OMAP4430_CM_L4CFG_MAILBOX_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_sar_rom = { + .name = "SAR_ROM", + .clkctrl = OMAP4430_CM_L4CFG_SAR_ROM_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_dmm = { + .name = "DMM", + .clkctrl = OMAP4430_CM_MEMIF_DMM_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_emif_1 = { + .name = "EMIF_1", + .clkctrl = OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_emif_2 = { + .name = "EMIF_2", + .clkctrl = OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_emif_fw = { + .name = "EMIF_FW", + .clkctrl = OMAP4430_CM_MEMIF_EMIF_FW_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_dll = { + .name = "DLL", + .clkctrl = OMAP4430_CM_MEMIF_DLL_CLKCTRL, + .flags = 0, + .optclk = 0x100, +}; + +static struct d_mod_info mod_cortexm3 = { + .name = "CORTEXM3", + .clkctrl = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_gpmc = { + .name = "GPMC", + .clkctrl = OMAP4430_CM_L3_2_GPMC_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_l3_2_interconnect = { + .name = "L3_2 interconnect", + .clkctrl = OMAP4430_CM_L3_2_L3_2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_ocmc_ram = { + .name = "OCMC_RAM", + .clkctrl = OMAP4430_CM_L3_2_OCMC_RAM_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_l3_3_interconnect = { + .name = "L3_3 interconnect", + .clkctrl = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_l3_instr_interconnect = { + .name = "L3_INSTR interconnect", + .clkctrl = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_wp1 = { + .name = "WP1", + .clkctrl = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_l3_1_interconnect = { + .name = "L3_1 interconnect", + .clkctrl = OMAP4430_CM_L3_1_L3_1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_c2c = { + .name = "C2C", + .clkctrl = OMAP4430_CM_D2D_SAD2D_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_c2c_fw = { + .name = "C2C_FW", + .clkctrl = OMAP4430_CM_D2D_SAD2D_FW_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + + +static struct d_mod_info mod_sdma = { + .name = "sDMA", + .clkctrl = OMAP4430_CM_SDMA_SDMA_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_dss = { + .name = "DSS", + .clkctrl = OMAP4430_CM_DSS_DSS_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0xf00, +}; + +static struct d_mod_info mod_sgx = { + .name = "SGX", + .clkctrl = OMAP4430_CM_GFX_GFX_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_hsi = { + .name = "HSI", + .clkctrl = OMAP4430_CM_L3INIT_HSI_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_hsmmc1 = { + .name = "HSMMC1", + .clkctrl = OMAP4430_CM_L3INIT_MMC1_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_hsmmc2 = { + .name = "HSMMC2", + .clkctrl = OMAP4430_CM_L3INIT_MMC2_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_usbphy = { + .name = "USBPHY", + .clkctrl = OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x100, +}; + +static struct d_mod_info mod_fsusb = { + .name = "FSUSB", + .clkctrl = OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_hsusbhost = { + .name = "HSUSBHOST", + .clkctrl = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0xff00, +}; + +static struct d_mod_info mod_hsusbotg = { + .name = "HSUSBOTG", + .clkctrl = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x100, +}; + +static struct d_mod_info mod_usbtll = { + .name = "USBTLL", + .clkctrl = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x300, +}; + +static struct d_mod_info mod_gptimer10 = { + .name = "GPTIMER10", + .clkctrl = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_gptimer11 = { + .name = "GPTIMER11", + .clkctrl = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_gptimer2 = { + .name = "GPTIMER2", + .clkctrl = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_gptimer3 = { + .name = "GPTIMER3", + .clkctrl = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_gptimer4 = { + .name = "GPTIMER4", + .clkctrl = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_gptimer9 = { + .name = "GPTIMER9", + .clkctrl = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_elm = { + .name = "ELM", + .clkctrl = OMAP4430_CM_L4PER_ELM_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_gpio2 = { + .name = "GPIO2", + .clkctrl = OMAP4430_CM_L4PER_GPIO2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x100, +}; +static struct d_mod_info mod_gpio3 = { + .name = "GPIO3", + .clkctrl = OMAP4430_CM_L4PER_GPIO3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x100, +}; +static struct d_mod_info mod_gpio4 = { + .name = "GPIO4", + .clkctrl = OMAP4430_CM_L4PER_GPIO4_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x100, +}; +static struct d_mod_info mod_gpio5 = { + .name = "GPIO5", + .clkctrl = OMAP4430_CM_L4PER_GPIO5_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x100, +}; +static struct d_mod_info mod_gpio6 = { + .name = "GPIO6", + .clkctrl = OMAP4430_CM_L4PER_GPIO6_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x100, +}; +static struct d_mod_info mod_hdq = { + .name = "HDQ", + .clkctrl = OMAP4430_CM_L4PER_HDQ1W_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_i2c1 = { + .name = "I2C1", + .clkctrl = OMAP4430_CM_L4PER_I2C1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_i2c2 = { + .name = "I2C2", + .clkctrl = OMAP4430_CM_L4PER_I2C2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_i2c3 = { + .name = "I2C3", + .clkctrl = OMAP4430_CM_L4PER_I2C3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_i2c4 = { + .name = "I2C4", + .clkctrl = OMAP4430_CM_L4PER_I2C4_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_l4_per_interconnect = { + .name = "L4_PER interconnect", + .clkctrl = OMAP4430_CM_L4PER_L4PER_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcbsp4 = { + .name = "MCBSP4", + .clkctrl = OMAP4430_CM_L4PER_MCBSP4_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcspi1 = { + .name = "MCSPI1", + .clkctrl = OMAP4430_CM_L4PER_MCSPI1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcspi2 = { + .name = "MCSPI2", + .clkctrl = OMAP4430_CM_L4PER_MCSPI2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcspi3 = { + .name = "MCSPI3", + .clkctrl = OMAP4430_CM_L4PER_MCSPI3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcspi4 = { + .name = "MCSPI4", + .clkctrl = OMAP4430_CM_L4PER_MCSPI4_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_hsmmc3 = { + .name = "HSMMC3", + .clkctrl = OMAP4430_CM_L4PER_MMCSD3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_hsmmc4 = { + .name = "HSMMC4", + .clkctrl = OMAP4430_CM_L4PER_MMCSD4_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_hsmmc5 = { + .name = "HSMMC5", + .clkctrl = OMAP4430_CM_L4PER_MMCSD5_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_slimbus2 = { + .name = "SLIMBUS2", + .clkctrl = OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x700, +}; +static struct d_mod_info mod_uart1 = { + .name = "UART1", + .clkctrl = OMAP4430_CM_L4PER_UART1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_uart2 = { + .name = "UART2", + .clkctrl = OMAP4430_CM_L4PER_UART2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_uart3 = { + .name = "UART3", + .clkctrl = OMAP4430_CM_L4PER_UART3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_uart4 = { + .name = "UART4", + .clkctrl = OMAP4430_CM_L4PER_UART4_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_audio_engine = { + .name = "AUDIO ENGINE", + .clkctrl = OMAP4430_CM1_ABE_AESS_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_dmic = { + .name = "DMIC", + .clkctrl = OMAP4430_CM1_ABE_DMIC_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_l4_abe_interconnect = { + .name = "L4_ABE interconnect", + .clkctrl = OMAP4430_CM1_ABE_L4ABE_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcasp1 = { + .name = "MCASP1", + .clkctrl = OMAP4430_CM1_ABE_MCASP_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcbsp1 = { + .name = "MCBSP1", + .clkctrl = OMAP4430_CM1_ABE_MCBSP1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcbsp2 = { + .name = "MCBSP2", + .clkctrl = OMAP4430_CM1_ABE_MCBSP2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcbsp3 = { + .name = "MCBSP3", + .clkctrl = OMAP4430_CM1_ABE_MCBSP3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_mcpdm = { + .name = "MCPDM", + .clkctrl = OMAP4430_CM1_ABE_PDM_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_slimbus1 = { + .name = "SLIMBUS1", + .clkctrl = OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0xf00, +}; +static struct d_mod_info mod_gptimer5 = { + .name = "GPTIMER5", + .clkctrl = OMAP4430_CM1_ABE_TIMER5_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_gptimer6 = { + .name = "GPTIMER6", + .clkctrl = OMAP4430_CM1_ABE_TIMER6_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_gptimer7 = { + .name = "GPTIMER7", + .clkctrl = OMAP4430_CM1_ABE_TIMER7_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_gptimer8 = { + .name = "GPTIMER8", + .clkctrl = OMAP4430_CM1_ABE_TIMER8_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_wdtimer3 = { + .name = "WDTIMER3", + .clkctrl = OMAP4430_CM1_ABE_WDT3_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_ivahd = { + .name = "IVAHD", + .clkctrl = OMAP4430_CM_IVAHD_IVAHD_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; +static struct d_mod_info mod_sl2 = { + .name = "SL2", + .clkctrl = OMAP4430_CM_IVAHD_SL2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_dsp = { + .name = "DSP", + .clkctrl = OMAP4430_CM_TESLA_TESLA_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_cortexa9 = { + .name = "CORTEXA9", + .clkctrl = OMAP4430_CM_MPU_MPU_CLKCTRL, + .flags = MOD_MODE | MOD_MASTER | MOD_SLAVE, + .optclk = 0x0, +}; + +/* L4SEC modules not in TRM, below based on Linux code */ + +static struct d_mod_info mod_aes1 = { + .name = "AES1", + .clkctrl = OMAP4430_CM_L4SEC_AES1_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_aes2 = { + .name = "AES2", + .clkctrl = OMAP4430_CM_L4SEC_AES2_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_des3des = { + .name = "DES3DES", + .clkctrl = OMAP4430_CM_L4SEC_DES3DES_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_pkaeip29 = { + .name = "PKAEIP29", + .clkctrl = OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_rng = { + .name = "RNG", + .clkctrl = OMAP4430_CM_L4SEC_RNG_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_sha2md51 = { + .name = "SHA2MD51", + .clkctrl = OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +static struct d_mod_info mod_cryptodma = { + .name = "CRYPTODMA", + .clkctrl = OMAP4430_CM_L4SEC_CRYPTODMA_CLKCTRL, + .flags = MOD_MODE | MOD_SLAVE, + .optclk = 0x0, +}; + +/* Clock domains */ + +struct d_clkd_info { + char *name; + const u8 prcm_partition; + const s16 cm_inst; + const u16 clkdm_offs; + int activity; + struct d_dpll_info *dplls[20]; + struct d_intgen_info *intgens[20]; + struct d_mod_info *mods[]; +}; + +static struct d_clkd_info cd_emu = { + .name = "CD_EMU", + .prcm_partition = OMAP4430_PRM_PARTITION, + .cm_inst = OMAP4430_PRM_EMU_CM_INST, + .clkdm_offs = OMAP4430_PRM_EMU_CM_EMU_CDOFFS, + .activity = 0x300, + .mods = {&mod_debug, NULL}, + .intgens = {NULL}, + // TBD: TRM mentions: CM1_EMU +}; + +static struct d_clkd_info cd_wkup = { + .name = "CD_WKUP", + .prcm_partition = OMAP4430_PRM_PARTITION, + .cm_inst = OMAP4430_PRM_WKUP_CM_INST, + .clkdm_offs = OMAP4430_PRM_WKUP_CM_WKUP_CDOFFS, + .activity = 0x1b00, + .mods = {&mod_bandgap, &mod_gpio1, &mod_keyboard, &mod_sar_ram, + &mod_32ktimer, &mod_gptimer1, &mod_wdtimer2, + &mod_l4_wkup, NULL}, + .intgens = {NULL}, + // TBD: TRM mentions: SYSCTRL_PADCONF_WKUP, SYSCTRL_GENERAL_WKUP, PRM, + // SCRM +}; + +static struct d_clkd_info cd_l4_alwon_core = { + .name = "CD_L4_ALWON_CORE", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_ALWAYS_ON_INST, + .clkdm_offs = OMAP4430_CM2_ALWAYS_ON_ALWON_CDOFFS, + .activity = 0xf00, + .mods = {&mod_sr_core, &mod_sr_iva, &mod_sr_mpu, NULL}, + .dplls = {&dpll_per, &dpll_core, &dpll_abe, NULL}, + .intgens = {NULL}, + // TBD: TRM mentions: CM1, CORTEXM3_WKUPGEN, SDMA_WKUPGEN, SPINNER +}; + +static struct d_clkd_info cd_cam = { + .name = "CD_CAM", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CAM_INST, + .clkdm_offs = OMAP4430_CM2_CAM_CAM_CDOFFS, + .activity = 0x700, + .mods = {&mod_fdif, &mod_iss, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_l4_cfg = { + .name = "CD_L4_CFG", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CORE_INST, + .clkdm_offs = OMAP4430_CM2_CORE_L4CFG_CDOFFS, + .activity = 0x100, + .mods = {&mod_spinlock, &mod_l4_cfg_interconnect, &mod_mailbox, + &mod_sar_rom, NULL}, + .intgens = {NULL}, + // TBD: TRM mentions: SYSCTRL_PADCONF_CORE, SYSCTRL_GENERAL_CORE +}; + +static struct d_clkd_info cd_emif = { + .name = "CD_EMIF", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CORE_INST, + .clkdm_offs = OMAP4430_CM2_CORE_MEMIF_CDOFFS, + .activity = 0x700, + .mods = {&mod_dmm, &mod_emif_1, &mod_emif_2, &mod_emif_fw, + &mod_dll, NULL}, + .intgens = {NULL}, + // TBD: TRM mentions: DDRPHY +}; + +static struct d_clkd_info cd_cortexm3 = { + .name = "CD_CORTEXM3", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CORE_INST, + .clkdm_offs = OMAP4430_CM2_CORE_DUCATI_CDOFFS, + .activity = 0x100, + .mods = {&mod_cortexm3, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_l3_2 = { + .name = "CD_L3_2", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CORE_INST, + .clkdm_offs = OMAP4430_CM2_CORE_L3_2_CDOFFS, + .activity = 0x100, + .mods = {&mod_gpmc, &mod_l3_2_interconnect, &mod_ocmc_ram, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_l3_instr = { + .name = "CD_L3_INSTR", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CORE_INST, + .clkdm_offs = OMAP4430_CM2_CORE_L3INSTR_CDOFFS, + .activity = 0x100, + .mods = {&mod_l3_3_interconnect, &mod_l3_instr_interconnect, + &mod_wp1, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_l3_1 = { + .name = "CD_L3_1", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CORE_INST, + .clkdm_offs = OMAP4430_CM2_CORE_L3_1_CDOFFS, + .activity = 0x100, + .mods = {&mod_l3_1_interconnect, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_c2c = { + .name = "CD_C2C", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CORE_INST, + .clkdm_offs = OMAP4430_CM2_CORE_D2D_CDOFFS, + .activity = 0x700, + .mods = {&mod_c2c, &mod_c2c_fw, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_dma = { + .name = "CD_DMA", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_CORE_INST, + .clkdm_offs = OMAP4430_CM2_CORE_SDMA_CDOFFS, + .activity = 0x100, + .mods = {&mod_sdma, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_dss = { + .name = "CD_DSS", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_DSS_INST, + .clkdm_offs = OMAP4430_CM2_DSS_DSS_CDOFFS, + .activity = 0xf00, + .mods = {&mod_dss, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_sgx = { + .name = "CD_SGX", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_GFX_INST, + .clkdm_offs = OMAP4430_CM2_GFX_GFX_CDOFFS, + .activity = 0x300, + .mods = {&mod_sgx, NULL}, +}; + +static struct d_clkd_info cd_l3_init = { + .name = "CD_L3_INIT", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_L3INIT_INST, + .clkdm_offs = OMAP4430_CM2_L3INIT_L3INIT_CDOFFS, + .activity = 0x3ef7f300, + .mods = {&mod_hsi, &mod_hsmmc1, &mod_hsmmc2, &mod_usbphy, + &mod_fsusb, &mod_hsusbhost, &mod_hsusbotg, &mod_usbtll, + NULL}, + .dplls = {&dpll_usb, NULL}, + .intgens = {NULL}, + // TBD: TRM mentions: CM1_USB +}; + +static struct d_clkd_info cd_l4_per = { + .name = "CD_L4_PER", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_L4PER_INST, + .clkdm_offs = OMAP4430_CM2_L4PER_L4PER_CDOFFS, + .activity = 0x24fff00, + .mods = {&mod_gptimer10, &mod_gptimer11, &mod_gptimer2, + &mod_gptimer3, &mod_gptimer4, &mod_gptimer9, &mod_elm, + &mod_gpio2, &mod_gpio3, &mod_gpio4, &mod_gpio5, &mod_gpio6, + &mod_hdq, &mod_i2c1, &mod_i2c2, &mod_i2c3, &mod_i2c4, + &mod_l4_per_interconnect, &mod_mcbsp4, &mod_mcspi1, + &mod_mcspi2, &mod_mcspi3, &mod_mcspi4, &mod_hsmmc3, + &mod_hsmmc4, &mod_hsmmc5, &mod_slimbus2, &mod_uart1, + &mod_uart2, &mod_uart3, &mod_uart4, NULL}, + // TBD: Linux refs: I2C5 + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_abe = { + .name = "CD_ABE", + .prcm_partition = OMAP4430_CM1_PARTITION, + .cm_inst = OMAP4430_CM1_ABE_INST, + .clkdm_offs = OMAP4430_CM1_ABE_ABE_CDOFFS, + .activity = 0x3400, + .mods = {&mod_audio_engine, &mod_dmic, &mod_l4_abe_interconnect, + &mod_mcasp1, &mod_mcbsp1, &mod_mcbsp2, &mod_mcbsp3, + &mod_mcpdm, &mod_slimbus1, &mod_gptimer5, &mod_gptimer6, + &mod_gptimer7, &mod_gptimer8, &mod_wdtimer3, NULL}, + .intgens = {&intgen_cm1_abe, NULL}, +}; + +static struct d_clkd_info cd_ivahd = { + .name = "CD_IVAHD", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_IVAHD_INST, + .clkdm_offs = OMAP4430_CM2_IVAHD_IVAHD_CDOFFS, + .activity = 0x100, + .mods = {&mod_ivahd, &mod_sl2, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_dsp = { + .name = "CD_DSP", + .prcm_partition = OMAP4430_CM1_PARTITION, + .cm_inst = OMAP4430_CM1_TESLA_INST, + .clkdm_offs = OMAP4430_CM1_TESLA_TESLA_CDOFFS, + .activity = 0x100, + .mods = {&mod_dsp, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_pd_alwon_mpu_fake = { + .name = "N/A (clock generator)", + .prcm_partition = -1, + .cm_inst = -1, + .clkdm_offs = -1, + .activity = 0x0, + .mods = {NULL}, + .dplls = {&dpll_mpu, NULL}, + .intgens = {NULL}, + // TBD: TRM mentions: CORTEXA9_MPU_INTC +}; + +static struct d_clkd_info cd_pd_alwon_dsp_fake = { + .name = "N/A (clock generator)", + .prcm_partition = -1, + .cm_inst = -1, + .clkdm_offs = -1, + .activity = 0x0, + .mods = {NULL}, + .dplls = {&dpll_iva, NULL}, + .intgens = {NULL}, + // TBD: TRM mentions: DSP_WKUPGEN +}; + +static struct d_clkd_info cd_cortexa9 = { + .name = "CD_CORTEXA9", + .prcm_partition = OMAP4430_CM1_PARTITION, + .cm_inst = OMAP4430_CM1_MPU_INST, + .clkdm_offs = OMAP4430_CM1_MPU_MPU_CDOFFS, + .activity = 0x100, + .mods = {&mod_cortexa9, NULL}, + .intgens = {NULL}, +}; + +static struct d_clkd_info cd_l4sec = { + .name = "CD_L4SEC", + .prcm_partition = OMAP4430_CM2_PARTITION, + .cm_inst = OMAP4430_CM2_L4PER_INST, + .clkdm_offs = OMAP4430_CM2_L4PER_L4SEC_CDOFFS, + .activity = 0x300, + .mods = {&mod_aes1, &mod_aes2, &mod_des3des, &mod_pkaeip29, &mod_rng, + &mod_sha2md51, &mod_cryptodma, NULL}, + .intgens = {NULL}, +}; + +#if 0 /* Don't appear to be valid */ +/* CD_MPU0 and MPU1 not in TRM, below based on Linux code. */ + +static struct d_clkd_info cd_mpu0 = { + .name = "CD_MPU0", + .prcm_partition = OMAP4430_PRCM_MPU_PARTITION, + .cm_inst = OMAP4430_PRCM_MPU_CPU0_INST, + .clkdm_offs = OMAP4430_PRCM_MPU_CPU0_CPU0_CDOFFS, + .activity = 0x0, + .mods = {NULL}, + .intgens = {NULL}, // TBD: No docs +}; + +static struct d_clkd_info cd_mpu1 = { + .name = "CD_MPU1", + .prcm_partition = OMAP4430_PRCM_MPU_PARTITION, + .cm_inst = OMAP4430_PRCM_MPU_CPU1_INST, + .clkdm_offs = OMAP4430_PRCM_MPU_CPU1_CPU1_CDOFFS, + .activity = 0x0, + .mods = {NULL}, + .intgens = {NULL}, // TBD: No docs +}; +#endif + +/* Power domains */ + +struct d_pwrd_info { + char *name; + long prminst; + int pwrst; + struct d_clkd_info *cds[]; +}; + +static struct d_pwrd_info pd_emu = { + .name = "PD_EMU", + .prminst = OMAP4430_PRM_EMU_INST, + .pwrst = OMAP4_PM_EMU_PWRSTST_OFFSET, + .cds = {&cd_emu, NULL}, +}; + +static struct d_pwrd_info pd_wkup = { + .name = "PD_WKUP", + .prminst = OMAP4430_PRM_WKUP_INST, + .pwrst = -1, + .cds = {&cd_wkup, NULL}, +}; + +static struct d_pwrd_info pd_alwon_core = { + .name = "PD_ALWON_CORE", + .prminst = OMAP4430_PRM_ALWAYS_ON_INST, + .pwrst = -1, + .cds = {&cd_l4_alwon_core, NULL}, +}; + +static struct d_pwrd_info pd_cam = { + .name = "PD_CAM", + .prminst = OMAP4430_PRM_CAM_INST, + .pwrst = OMAP4_PM_CAM_PWRSTST_OFFSET, + .cds = {&cd_cam, NULL}, +}; + +static struct d_pwrd_info pd_core = { + .name = "PD_CORE", + .prminst = OMAP4430_PRM_CORE_INST, + .pwrst = OMAP4_PM_CORE_PWRSTST_OFFSET, + .cds = {&cd_l4_cfg, &cd_emif, &cd_cortexm3, &cd_l3_2, &cd_l3_instr, + &cd_l3_1, &cd_c2c, &cd_dma, NULL}, + // TBD: TRM mentions: CM2 +}; + +static struct d_pwrd_info pd_dss = { + .name = "PD_DSS", + .prminst = OMAP4430_PRM_DSS_INST, + .pwrst = OMAP4_PM_DSS_PWRSTST_OFFSET, + .cds = {&cd_dss, NULL}, +}; + +static struct d_pwrd_info pd_sgx = { + .name = "PD_SGX", + .prminst = OMAP4430_PRM_GFX_INST, + .pwrst = OMAP4_PM_GFX_PWRSTST_OFFSET, + .cds = {&cd_sgx, NULL}, +}; + +static struct d_pwrd_info pd_l3_init = { + .name = "PD_L3_INIT", + .prminst = OMAP4430_PRM_L3INIT_INST, + .pwrst = OMAP4_PM_L3INIT_PWRSTST_OFFSET, + .cds = {&cd_l3_init, NULL}, +}; + +static struct d_pwrd_info pd_l4_per = { + .name = "PD_L4_PER", + .prminst = OMAP4430_PRM_L4PER_INST, + .pwrst = OMAP4_PM_L4PER_PWRSTST_OFFSET, + .cds = {&cd_l4_per, &cd_l4sec, NULL}, +}; + +static struct d_pwrd_info pd_std_efuse = { + .name = "PD_STD_EFUSE", + .prminst = -1, + .pwrst = -1, + .cds = {NULL}, +}; + +static struct d_pwrd_info pd_alwon_dsp = { + .name = "PD_ALWON_DSP", + .prminst = -1, + .pwrst = -1, + .cds = {&cd_pd_alwon_dsp_fake, NULL}, +}; + +static struct d_pwrd_info pd_audio = { + .name = "PD_AUDIO", + .prminst = OMAP4430_PRM_ABE_INST, + .pwrst = OMAP4_PM_ABE_PWRSTST_OFFSET, + .cds = {&cd_abe, NULL}, +}; + +static struct d_pwrd_info pd_ivahd = { + .name = "PD_IVAHD", + .prminst = OMAP4430_PRM_IVAHD_INST, + .pwrst = OMAP4_PM_IVAHD_PWRSTST_OFFSET, + .cds = {&cd_ivahd, NULL}, +}; + +static struct d_pwrd_info pd_dsp = { + .name = "PD_DSP", + .prminst = OMAP4430_PRM_TESLA_INST, + .pwrst = OMAP4_PM_TESLA_PWRSTST_OFFSET, + .cds = {&cd_dsp, NULL}, +}; + +static struct d_pwrd_info pd_alwon_mpu = { + .name = "PD_ALWON_MPU", + .prminst = -1, + .pwrst = -1, + .cds = {&cd_pd_alwon_mpu_fake, NULL}, +}; + +static struct d_pwrd_info pd_mpu = { + .name = "PD_MPU", + .prminst = OMAP4430_PRM_MPU_INST, + .pwrst = OMAP4_PM_MPU_PWRSTST_OFFSET, + .cds = {&cd_cortexa9, NULL}, +}; + +#if 0 /* Do not seem to be valid */ +/* CPU0 and CPU1 power domains not in TRM, below based on Linux code */ + +static struct d_pwrd_info pd_cpu0 = { + .name = "PD_CPU0", + .prminst = OMAP4430_PRCM_MPU_CPU0_INST, + .pwrst = OMAP4_PM_CPU0_PWRSTST_OFFSET, + .cds = {&cd_mpu0, NULL}, +}; + +static struct d_pwrd_info pd_cpu1 = { + .name = "PD_CPU1", + .prminst = OMAP4430_PRCM_MPU_CPU1_INST, + .pwrst = OMAP4_PM_CPU1_PWRSTST_OFFSET, + .cds = {&cd_mpu1, NULL}, +}; +#endif + +/* Voltage domains to power domains */ + +static struct d_pwrd_info *ldo_wakeup_pds[] = +{&pd_emu, &pd_wkup, NULL}; + +static struct d_pwrd_info *vdd_core_pds[] = +{&pd_alwon_core, &pd_cam, &pd_core, &pd_dss, &pd_sgx, &pd_l3_init, &pd_l4_per, + &pd_std_efuse, NULL}; + +static struct d_pwrd_info *vdd_iva_pds[] = +{&pd_alwon_dsp, &pd_audio, &pd_ivahd, &pd_dsp, NULL}; + +static struct d_pwrd_info *vdd_mpu_pds[] = +{&pd_alwon_mpu, &pd_mpu, /* &pd_cpu0, &pd_cpu1, */ NULL}; + +/* Voltage domains */ + +#define N_VDDS 4 + +struct d_vdd_info { + char *name; + int auto_ctrl_shift; + int auto_ctrl_mask; + struct d_pwrd_info **pds; +}; + +static struct d_vdd_info d_vdd[N_VDDS] = { + { + .name = "LDO_WAKEUP", + .auto_ctrl_shift = -1, + .auto_ctrl_mask = -1, + .pds = ldo_wakeup_pds, + }, + { + .name = "VDD_CORE_L", + .auto_ctrl_shift = OMAP4430_AUTO_CTRL_VDD_CORE_L_SHIFT, + .auto_ctrl_mask = OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK, + .pds = vdd_core_pds, + }, + { + .name = "VDD_IVA_L", + .auto_ctrl_shift = OMAP4430_AUTO_CTRL_VDD_IVA_L_SHIFT, + .auto_ctrl_mask = OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK, + .pds = vdd_iva_pds, + }, + { + .name = "VDD_MPU_L", + .auto_ctrl_shift = OMAP4430_AUTO_CTRL_VDD_MPU_L_SHIFT, + .auto_ctrl_mask = OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK, + .pds = vdd_mpu_pds, + }, +}; + + +/* Display strings */ + +static char *vddauto_s[] = {"disabled", "SLEEP", "RET", "reserved"}; + +static char *pwrstate_s[] = {"OFF", "RET", "INACTIVE", "ON"}; + +static char *logic_s[] = {"OFF", "ON"}; + +static char *cmtrctrl_s[] = {"NOSLEEP", "SW_SLEEP", "SW_WKUP", "HW_AUTO"}; + +static char *modmode_s[] = {"DISABLED", "AUTO", "ENABLED", "3"}; + +static char *modstbyst_s[] = {"ON", "STBY"}; + +static char *modidlest_s[] = {"ON", "TRANSITION", "IDLE", "DISABLED"}; + +#if 0 +#define DEP_S_MAX 19 + +static char *dep_s[DEP_S_MAX] = {"MPU_M3", "DSP", "IVAHD", "ABE", "MEMIF", + "L3_1", "L3_2", "L3INIT", "DSS", "ISS", + "GFX", "SDMA", "L4CFG", "L4PER", "L4SEC", + "L4WKUP", "ALWON_CORE", "STD_EFUSE", + "D2D"}; +#endif + +#define d_pr(sf, fmt, args...) \ + { \ + if (sf) \ + seq_printf(sf, fmt , ## args); \ + else \ + pr_info(fmt , ## args); \ + } + +#define d_pr_ctd(sf, fmt, args...) \ + { \ + if (sf) \ + seq_printf(sf, fmt , ## args); \ + else \ + pr_cont(fmt , ## args); \ + } + +static void prcmdebug_dump_dpll(struct seq_file *sf, + struct d_dpll_info *dpll, + int flags) +{ + u32 idlest = __raw_readl(dpll->idlestreg); + u32 st_bypass = idlest & OMAP4430_ST_MN_BYPASS_MASK; + u32 st_dpll_clk = idlest & OMAP4430_ST_DPLL_CLK_MASK; + struct d_dpll_derived **derived; + + if (flags & (PRCMDEBUG_LASTSLEEP | PRCMDEBUG_ON) && !st_dpll_clk) + return; + + d_pr(sf, " %s status=%s\n", dpll->name, + st_dpll_clk ? "locked" : st_bypass ? "bypass" : "stopped"); + + derived = dpll->derived; + + while (*derived) { + u32 enabled = __raw_readl((*derived)->gatereg) & + (*derived)->gatemask; + + if (!(flags & (PRCMDEBUG_LASTSLEEP | PRCMDEBUG_ON)) || + enabled) + d_pr(sf, " %s enabled=0x%x\n", + (*derived)->name, enabled); + derived++; + } +} + + +static void prcmdebug_dump_intgen(struct seq_file *sf, + struct d_intgen_info *intgen, + int flags) +{ + u32 enabled = __raw_readl(intgen->gatereg) & intgen->gatemask; + + if (flags & (PRCMDEBUG_LASTSLEEP | PRCMDEBUG_ON) && !enabled) + return; + + d_pr(sf, " %s enabled=0x%x\n", intgen->name, enabled); +} + +static void prcmdebug_dump_mod(struct seq_file *sf, struct d_mod_info *mod, + int flags) +{ + u32 clkctrl = __raw_readl(mod->clkctrl); + u32 stbyst = (clkctrl & OMAP4430_STBYST_MASK) >> OMAP4430_STBYST_SHIFT; + u32 idlest = (clkctrl & OMAP4430_IDLEST_MASK) >> OMAP4430_IDLEST_SHIFT; + u32 optclk = clkctrl & mod->optclk; + + if (flags & (PRCMDEBUG_LASTSLEEP | PRCMDEBUG_ON) && + (!(mod->flags & MOD_MASTER) || stbyst == 1) && + (!(mod->flags & MOD_SLAVE) || idlest == 2 || idlest == 3) && + !optclk) + return; + + if (flags & PRCMDEBUG_LASTSLEEP && + (mod->flags & MOD_MODE && + ((clkctrl & OMAP4430_MODULEMODE_MASK) >> + OMAP4430_MODULEMODE_SHIFT) == 1 /* AUTO */) && + (!(mod->flags & MOD_SLAVE) || idlest == 0) /* ON */ && + !optclk) + return; + + d_pr(sf, " %s", mod->name); + + if (mod->flags & MOD_MODE) + d_pr_ctd(sf, " mode=%s", + modmode_s[(clkctrl & OMAP4430_MODULEMODE_MASK) >> + OMAP4430_MODULEMODE_SHIFT]); + + if (mod->flags & MOD_MASTER) + d_pr_ctd(sf, " stbyst=%s", + modstbyst_s[stbyst]); + + if (mod->flags & MOD_SLAVE) + d_pr_ctd(sf, " idlest=%s", + modidlest_s[idlest]); + + if (optclk) + d_pr_ctd(sf, " optclk=0x%x", optclk); + + d_pr_ctd(sf, "\n"); +} + +static void prcmdebug_dump_real_cd(struct seq_file *sf, struct d_clkd_info *cd, + int flags) +{ + u32 clktrctrl = + omap4_cminst_read_inst_reg(cd->prcm_partition, cd->cm_inst, + cd->clkdm_offs + OMAP4_CM_CLKSTCTRL); + u32 mode = (clktrctrl & OMAP4430_CLKTRCTRL_MASK) >> + OMAP4430_CLKTRCTRL_SHIFT; + u32 activity = clktrctrl & cd->activity; +#if 0 + u32 staticdep = + omap4_cminst_read_inst_reg(cd->prcm_partition, cd->cm_inst, + cd->clkdm_offs + OMAP4_CM_STATICDEP); + u32 dynamicdep = + omap4_cminst_read_inst_reg(cd->prcm_partition, cd->cm_inst, + cd->clkdm_offs + + OMAP4_CM_STATICDEP + 4) & 0xffffff; + int i; +#endif + + if (flags & PRCMDEBUG_LASTSLEEP && mode == 3 /* HW_AUTO */) + return; + + d_pr(sf, " %s mode=%s", cd->name, cmtrctrl_s[mode]); + + d_pr_ctd(sf, " activity=0x%x", activity); + +#if 0 + if (staticdep) { + d_pr_ctd(sf, " static:"); + + for (i = 0; i < DEP_S_MAX; i++) + if (staticdep & (1 << i)) + d_pr_ctd(sf, " %s", dep_s[i]); + } +#endif + +#if 0 + if (dynamicdep) + d_pr_ctd(sf, " dynamicdep=0x%x", dynamicdep); +#endif + + d_pr_ctd(sf, "\n"); +} + +static void prcmdebug_dump_cd(struct seq_file *sf, struct d_clkd_info *cd, + int flags) +{ + struct d_mod_info **mod; + struct d_intgen_info **intgen; + struct d_dpll_info **dpll; + + if (cd->cm_inst != -1) { + prcmdebug_dump_real_cd(sf, cd, flags); + } else if (!(flags & PRCMDEBUG_LASTSLEEP)) { + d_pr(sf, " %s\n", cd->name); + } + + mod = cd->mods; + + while (*mod) { + prcmdebug_dump_mod(sf, *mod, flags); + mod++; + } + + dpll = cd->dplls; + + while (*dpll) { + prcmdebug_dump_dpll(sf, *dpll, flags); + dpll++; + } + + intgen = cd->intgens; + + while (*intgen) { + prcmdebug_dump_intgen(sf, *intgen, flags); + intgen++; + } +} + +static void prcmdebug_dump_pd(struct seq_file *sf, struct d_pwrd_info *pd, + int flags) +{ + u32 pwrstst, currst, prevst; + struct d_clkd_info **cd; + + if (pd->pwrst != -1 && pd->prminst != -1) { + pwrstst = omap4_prm_read_inst_reg(pd->prminst, pd->pwrst); + currst = (pwrstst & OMAP4430_POWERSTATEST_MASK) >> + OMAP4430_POWERSTATEST_SHIFT; + prevst = (pwrstst & OMAP4430_LASTPOWERSTATEENTERED_MASK) >> + OMAP4430_LASTPOWERSTATEENTERED_SHIFT; + + if (flags & PRCMDEBUG_LASTSLEEP && + (prevst == PWRDM_POWER_OFF || prevst == PWRDM_POWER_RET)) + return; + + if (flags & PRCMDEBUG_ON && + (currst == PWRDM_POWER_OFF || currst == PWRDM_POWER_RET)) + return; + + d_pr(sf, " %s curr=%s prev=%s logic=%s\n", pd->name, + pwrstate_s[currst], + pwrstate_s[prevst], + logic_s[(pwrstst & OMAP4430_LOGICSTATEST_MASK) >> + OMAP4430_LOGICSTATEST_SHIFT]); + } else { + if (flags & PRCMDEBUG_LASTSLEEP) + return; + + d_pr(sf, " %s\n", pd->name); + } + + cd = pd->cds; + + while (*cd) { + prcmdebug_dump_cd(sf, *cd, flags); + cd++; + } +} + +static int _prcmdebug_dump(struct seq_file *sf, int flags) +{ + int i; + u32 prm_voltctrl = + omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, + OMAP4_PRM_VOLTCTRL_OFFSET); + struct d_pwrd_info **pd; + + for (i = 0; i < N_VDDS; i++) { + if (!(flags & PRCMDEBUG_LASTSLEEP)) { + d_pr(sf, "%s", + d_vdd[i].name); + + if (d_vdd[i].auto_ctrl_shift != -1) { + int auto_ctrl = + (prm_voltctrl & + d_vdd[i].auto_ctrl_mask) >> + d_vdd[i].auto_ctrl_shift; + d_pr_ctd(sf, " auto=%s\n", + vddauto_s[auto_ctrl]); + } else { + d_pr_ctd(sf, " (no auto)\n"); + } + + } + + pd = d_vdd[i].pds; + + while (*pd) { + prcmdebug_dump_pd(sf, *pd, flags); + pd++; + } + } + + return 0; +} + +void prcmdebug_dump(int flags) +{ + _prcmdebug_dump(NULL, flags); +} + +static int prcmdebug_all_dump(struct seq_file *sf, void *private) +{ + _prcmdebug_dump(sf, 0); + return 0; +} + +static int prcmdebug_all_open(struct inode *inode, struct file *file) +{ + return single_open(file, prcmdebug_all_dump, NULL); +} + + +static struct file_operations prcmdebug_all_fops = { + .open = prcmdebug_all_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int prcmdebug_on_dump(struct seq_file *sf, void *private) +{ + _prcmdebug_dump(sf, PRCMDEBUG_ON); + return 0; +} + +static int prcmdebug_on_open(struct inode *inode, struct file *file) +{ + return single_open(file, prcmdebug_on_dump, NULL); +} + +static struct file_operations prcmdebug_on_fops = { + .open = prcmdebug_on_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init prcmdebug_init(void) +{ + if (IS_ERR_OR_NULL(debugfs_create_file("prcm", S_IRUGO, NULL, NULL, + &prcmdebug_all_fops))) + pr_err("%s: failed to create prcm file\n", __func__); + + if (IS_ERR_OR_NULL(debugfs_create_file("prcm-on", S_IRUGO, NULL, NULL, + &prcmdebug_on_fops))) + pr_err("%s: failed to create prcm-on file\n", __func__); + + return 0; +} + +arch_initcall(prcmdebug_init); diff --git a/arch/arm/mach-omap2/prcm-debug.h b/arch/arm/mach-omap2/prcm-debug.h new file mode 100644 index 0000000..14ca00fb --- /dev/null +++ b/arch/arm/mach-omap2/prcm-debug.h @@ -0,0 +1,13 @@ +#ifndef __ARCH_ASM_MACH_OMAP2_PRCM_DEBUG_H +#define __ARCH_ASM_MACH_OMAP2_PRCM_DEBUG_H + +#define PRCMDEBUG_LASTSLEEP (1 << 0) +#define PRCMDEBUG_ON (1 << 1) + +#ifdef CONFIG_PM_DEBUG +extern void prcmdebug_dump(int flags); +#else +static inline void prcmdebug_dump(int flags) { } +#endif + +#endif /* __ARCH_ASM_MACH_OMAP2_PRCM_DEBUG_H */ diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h index 64c087a..c38c459 100644 --- a/arch/arm/mach-omap2/prm-regbits-34xx.h +++ b/arch/arm/mach-omap2/prm-regbits-34xx.h @@ -216,6 +216,7 @@ /* PRM_SYSCONFIG specific bits */ /* PRM_IRQSTATUS_MPU specific bits */ +#define OMAP3630_ABB_LDO_TRANXDONE_ST_MASK (1 << 26) #define OMAP3430ES2_SND_PERIPH_DPLL_ST_SHIFT 25 #define OMAP3430ES2_SND_PERIPH_DPLL_ST_MASK (1 << 25) #define OMAP3430_VC_TIMEOUTERR_ST_MASK (1 << 24) diff --git a/arch/arm/mach-omap2/prm-regbits-44xx.h b/arch/arm/mach-omap2/prm-regbits-44xx.h index 6d2776f..b76cfd6 100644 --- a/arch/arm/mach-omap2/prm-regbits-44xx.h +++ b/arch/arm/mach-omap2/prm-regbits-44xx.h @@ -1,7 +1,7 @@ /* * OMAP44xx Power Management register bits * - * Copyright (C) 2009-2010 Texas Instruments, Inc. + * Copyright (C) 2009-2011 Texas Instruments, Inc. * Copyright (C) 2009-2010 Nokia Corporation * * Paul Walmsley (paul@pwsan.com) @@ -92,6 +92,10 @@ #define OMAP4430_AUTO_CTRL_VDD_MPU_L_SHIFT 2 #define OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK (0x3 << 2) +/* Used by PRM_VOLTCTRL */ +#define OMAP4430_AUTO_CTRL_VDD_RET_MASK (1 << 1) +#define OMAP4430_AUTO_CTRL_VDD_SLEEP_MASK (1 << 0) + /* Used by PRM_VC_ERRST */ #define OMAP4430_BYPS_RA_ERR_SHIFT 25 #define OMAP4430_BYPS_RA_ERR_MASK (1 << 25) @@ -283,6 +287,14 @@ #define OMAP4430_DUCATI_UNICACHE_STATEST_SHIFT 10 #define OMAP4430_DUCATI_UNICACHE_STATEST_MASK (0x3 << 10) +/* Used by PRM_DEVICE_OFF_CTRL */ +#define OMAP4460_EMIF1_OFFWKUP_DISABLE_SHIFT 8 +#define OMAP4460_EMIF1_OFFWKUP_DISABLE_MASK (1 << 8) + +/* Used by PRM_DEVICE_OFF_CTRL */ +#define OMAP4460_EMIF2_OFFWKUP_DISABLE_SHIFT 9 +#define OMAP4460_EMIF2_OFFWKUP_DISABLE_MASK (1 << 9) + /* Used by RM_MPU_RSTST */ #define OMAP4430_EMULATION_RST_SHIFT 0 #define OMAP4430_EMULATION_RST_MASK (1 << 0) @@ -390,6 +402,8 @@ /* Used by PRM_IO_PMCTRL */ #define OMAP4430_GLOBAL_WUEN_SHIFT 16 #define OMAP4430_GLOBAL_WUEN_MASK (1 << 16) +#define OMAP4430_ISOOVR_EXTEND_SHIFT 4 +#define OMAP4430_ISOOVR_EXTEND_MASK (1 << 4) /* Used by PRM_VC_CFG_I2C_MODE */ #define OMAP4430_HSMCODE_SHIFT 0 @@ -1063,6 +1077,14 @@ #define OMAP4430_SCLL_SHIFT 8 #define OMAP4430_SCLL_MASK (0xff << 8) +/* Used by PRM_VC_CFG_I2C_CLK */ +#define OMAP4430_HSCLH_SHIFT 16 +#define OMAP4430_HSCLH_MASK (0xff << 16) + +/* Used by PRM_VC_CFG_I2C_CLK */ +#define OMAP4430_HSCLL_SHIFT 24 +#define OMAP4430_HSCLL_MASK (0xff << 24) + /* Used by PRM_RSTST */ #define OMAP4430_SECURE_WDT_RST_SHIFT 4 #define OMAP4430_SECURE_WDT_RST_MASK (1 << 4) diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index 051213f..49e9719 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -20,6 +20,8 @@ #include <plat/cpu.h> #include <plat/prcm.h> +#include "vp.h" + #include "prm2xxx_3xxx.h" #include "cm2xxx_3xxx.h" #include "prm-regbits-24xx.h" @@ -156,3 +158,80 @@ int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift) return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; } + +/* PRM VP */ + +/* + * struct omap3_prm_irq - OMAP3 PRM IRQ register access description. + * @vp_tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg + * @abb_tranxdone_status: ABB_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg + * (ONLY for OMAP3630) + */ +struct omap3_prm_irq { + u32 vp_tranxdone_status; + u32 abb_tranxdone_status; +}; + +static struct omap3_prm_irq omap3_prm_irqs[] = { + [OMAP3_PRM_IRQ_VDD_MPU_ID] = { + .vp_tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK, + .abb_tranxdone_status = OMAP3630_ABB_LDO_TRANXDONE_ST_MASK, + }, + [OMAP3_PRM_IRQ_VDD_CORE_ID] = { + .vp_tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK, + /* no abb for core */ + }, +}; + +#define MAX_VP_ID ARRAY_SIZE(omap3_vp); + +u32 omap3_prm_vp_check_txdone(u8 irq_id) +{ + struct omap3_prm_irq *irq = &omap3_prm_irqs[irq_id]; + u32 irqstatus; + + irqstatus = omap2_prm_read_mod_reg(OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + return irqstatus & irq->vp_tranxdone_status; +} + +void omap3_prm_vp_clear_txdone(u8 irq_id) +{ + struct omap3_prm_irq *irq = &omap3_prm_irqs[irq_id]; + + omap2_prm_write_mod_reg(irq->vp_tranxdone_status, + OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); +} + +u32 omap36xx_prm_abb_check_txdone(u8 irq_id) +{ + struct omap3_prm_irq *irq = &omap3_prm_irqs[irq_id]; + u32 irqstatus; + + irqstatus = omap2_prm_read_mod_reg(OCP_MOD, + OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + return irqstatus & irq->abb_tranxdone_status; +} + +void omap36xx_prm_abb_clear_txdone(u8 irq_id) +{ + struct omap3_prm_irq *irq = &omap3_prm_irqs[irq_id]; + + omap2_prm_write_mod_reg(irq->abb_tranxdone_status, + OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); +} + +u32 omap3_prm_vcvp_read(u8 offset) +{ + return omap2_prm_read_mod_reg(OMAP3430_GR_MOD, offset); +} + +void omap3_prm_vcvp_write(u32 val, u8 offset) +{ + omap2_prm_write_mod_reg(val, OMAP3430_GR_MOD, offset); +} + +u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) +{ + return omap2_prm_rmw_mod_reg_bits(mask, bits, OMAP3430_GR_MOD, offset); +} diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index a1fc62a..08d5f1e 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h @@ -167,6 +167,10 @@ #define OMAP3430_PRM_VP2_VOLTAGE OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0) #define OMAP3_PRM_VP2_STATUS_OFFSET 0x00e4 #define OMAP3430_PRM_VP2_STATUS OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4) +#define OMAP3_PRM_LDO_ABB_SETUP_OFFSET 0x00f0 +#define OMAP3630_PRM_LDO_ABB_SETUP OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00f0) +#define OMAP3_PRM_LDO_ABB_CTRL_OFFSET 0x00f4 +#define OMAP3630_PRM_LDO_ABB_CTRL OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, 0x00f4) #define OMAP3_PRM_CLKSEL_OFFSET 0x0040 #define OMAP3430_PRM_CLKSEL OMAP34XX_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040) @@ -303,7 +307,25 @@ extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); +#define OMAP3_PRM_IRQ_VDD_MPU_ID 0 +#define OMAP3_PRM_IRQ_VDD_CORE_ID 1 +/* OMAP3-specific VP functions */ +u32 omap3_prm_vp_check_txdone(u8 irq_id); +void omap3_prm_vp_clear_txdone(u8 irq_id); + +/* OMAP36xx-specific ABB functions */ +u32 omap36xx_prm_abb_check_txdone(u8 irq_id); +void omap36xx_prm_abb_clear_txdone(u8 irq_id); + +/* + * OMAP3 access functions for voltage controller (VC) and + * voltage proccessor (VP) in the PRM. + */ +extern u32 omap3_prm_vcvp_read(u8 offset); +extern void omap3_prm_vcvp_write(u32 val, u8 offset); +extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); #endif /* CONFIG_ARCH_OMAP4 */ + #endif /* diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index a2a04bf..6f011e0 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -21,8 +21,12 @@ #include <plat/cpu.h> #include <plat/prcm.h> +#include "voltage.h" +#include "vp.h" #include "prm44xx.h" #include "prm-regbits-44xx.h" +#include "prcm44xx.h" +#include "prminst44xx.h" /* * Address offset (in bytes) between the reset control and the reset @@ -193,3 +197,112 @@ void omap4_prm_global_warm_sw_reset(void) v = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, OMAP4_RM_RSTCTRL); } + +void omap4_prm_global_cold_sw_reset(void) +{ + u32 v; + + v = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, + OMAP4_RM_RSTCTRL); + v |= OMAP4430_RST_GLOBAL_COLD_SW_MASK; + omap4_prm_write_inst_reg(v, OMAP4430_PRM_DEVICE_INST, + OMAP4_RM_RSTCTRL); + + /* OCP barrier */ + v = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, + OMAP4_RM_RSTCTRL); +} + +/* PRM VP */ + +/* + * struct omap4_prm_irq - OMAP4 VP register access description. + * @irqstatus_mpu: offset to IRQSTATUS_MPU register for VP + * @vp_tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg + * @abb_tranxdone_status: ABB_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg + */ +struct omap4_prm_irq { + u32 irqstatus_mpu; + u32 vp_tranxdone_status; + u32 abb_tranxdone_status; +}; + +static struct omap4_prm_irq omap4_prm_irqs[] = { + [OMAP4_PRM_IRQ_VDD_MPU_ID] = { + .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET, + .vp_tranxdone_status = OMAP4430_VP_MPU_TRANXDONE_ST_MASK, + .abb_tranxdone_status = OMAP4430_ABB_MPU_DONE_ST_MASK + }, + [OMAP4_PRM_IRQ_VDD_IVA_ID] = { + .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_OFFSET, + .vp_tranxdone_status = OMAP4430_VP_IVA_TRANXDONE_ST_MASK, + .abb_tranxdone_status = OMAP4430_ABB_IVA_DONE_ST_MASK, + }, + [OMAP4_PRM_IRQ_VDD_CORE_ID] = { + .irqstatus_mpu = OMAP4_PRM_IRQSTATUS_MPU_OFFSET, + .vp_tranxdone_status = OMAP4430_VP_CORE_TRANXDONE_ST_MASK, + /* Core has no ABB */ + }, +}; + +u32 omap4_prm_vp_check_txdone(u8 irq_id) +{ + struct omap4_prm_irq *irq = &omap4_prm_irqs[irq_id]; + u32 irqstatus; + + irqstatus = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_OCP_SOCKET_INST, + irq->irqstatus_mpu); + return irqstatus & irq->vp_tranxdone_status; +} + +void omap4_prm_vp_clear_txdone(u8 irq_id) +{ + struct omap4_prm_irq *irq = &omap4_prm_irqs[irq_id]; + + omap4_prminst_write_inst_reg(irq->vp_tranxdone_status, + OMAP4430_PRM_PARTITION, + OMAP4430_PRM_OCP_SOCKET_INST, + irq->irqstatus_mpu); +}; + +u32 omap4_prm_abb_check_txdone(u8 irq_id) +{ + struct omap4_prm_irq *irq = &omap4_prm_irqs[irq_id]; + u32 irqstatus; + + irqstatus = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_OCP_SOCKET_INST, + irq->irqstatus_mpu); + return irqstatus & irq->abb_tranxdone_status; +} + +void omap4_prm_abb_clear_txdone(u8 irq_id) +{ + struct omap4_prm_irq *irq = &omap4_prm_irqs[irq_id]; + + omap4_prminst_write_inst_reg(irq->abb_tranxdone_status, + OMAP4430_PRM_PARTITION, + OMAP4430_PRM_OCP_SOCKET_INST, + irq->irqstatus_mpu); +} + +u32 omap4_prm_vcvp_read(u8 offset) +{ + return omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, offset); +} + +void omap4_prm_vcvp_write(u32 val, u8 offset) +{ + omap4_prminst_write_inst_reg(val, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, offset); +} + +u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) +{ + return omap4_prminst_rmw_inst_reg_bits(mask, bits, + OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, + offset); +} diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h index 67a0d3f..ead36e1 100644 --- a/arch/arm/mach-omap2/prm44xx.h +++ b/arch/arm/mach-omap2/prm44xx.h @@ -713,8 +713,8 @@ #define OMAP4430_PRM_VC_VAL_BYPASS OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_INST, 0x00a0) #define OMAP4_PRM_VC_CFG_CHANNEL_OFFSET 0x00a4 #define OMAP4430_PRM_VC_CFG_CHANNEL OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_INST, 0x00a4) -#define OMAP4_PRM_VC_CFG_I2C_INSTE_OFFSET 0x00a8 -#define OMAP4430_PRM_VC_CFG_I2C_INSTE OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_INST, 0x00a8) +#define OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET 0x00a8 +#define OMAP4430_PRM_VC_CFG_I2C_MODE OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_INST, 0x00a8) #define OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET 0x00ac #define OMAP4430_PRM_VC_CFG_I2C_CLK OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_INST, 0x00ac) #define OMAP4_PRM_SRAM_COUNT_OFFSET 0x00b0 @@ -772,6 +772,25 @@ extern int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift); extern int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift); extern void omap4_prm_global_warm_sw_reset(void); +extern void omap4_prm_global_cold_sw_reset(void); + +#define OMAP4_PRM_IRQ_VDD_CORE_ID 0 +#define OMAP4_PRM_IRQ_VDD_IVA_ID 1 +#define OMAP4_PRM_IRQ_VDD_MPU_ID 2 +/* OMAP4-specific VP functions */ +u32 omap4_prm_vp_check_txdone(u8 irq_id); +void omap4_prm_vp_clear_txdone(u8 irq_id); +/* OMAP4-specific ABB functions */ +u32 omap4_prm_abb_check_txdone(u8 irq_id); +void omap4_prm_abb_clear_txdone(u8 irq_id); + +/* + * OMAP4 access functions for voltage controller (VC) and + * voltage proccessor (VP) in the PRM. + */ +extern u32 omap4_prm_vcvp_read(u8 offset); +extern void omap4_prm_vcvp_write(u32 val, u8 offset); +extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); # endif diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c index a303242..b6a286f 100644 --- a/arch/arm/mach-omap2/prminst44xx.c +++ b/arch/arm/mach-omap2/prminst44xx.c @@ -22,13 +22,14 @@ #include "prm-regbits-44xx.h" #include "prcm44xx.h" #include "prcm_mpu44xx.h" +#include "scrm44xx.h" static u32 _prm_bases[OMAP4_MAX_PRCM_PARTITIONS] = { [OMAP4430_INVALID_PRCM_PARTITION] = 0, [OMAP4430_PRM_PARTITION] = OMAP4430_PRM_BASE, [OMAP4430_CM1_PARTITION] = 0, [OMAP4430_CM2_PARTITION] = 0, - [OMAP4430_SCRM_PARTITION] = 0, + [OMAP4430_SCRM_PARTITION] = OMAP4_SCRM_BASE, [OMAP4430_PRCM_MPU_PARTITION] = OMAP4430_PRCM_MPU_BASE, }; diff --git a/arch/arm/mach-omap2/remoteproc.c b/arch/arm/mach-omap2/remoteproc.c new file mode 100644 index 0000000..b8ae36f --- /dev/null +++ b/arch/arm/mach-omap2/remoteproc.c @@ -0,0 +1,164 @@ +/* + * Remote processor machine-specific module for OMAP4 + * + * Copyright (C) 2011 Texas Instruments, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/remoteproc.h> +#include <linux/memblock.h> +#include <plat/omap_device.h> +#include <plat/omap_hwmod.h> +#include <plat/remoteproc.h> +#include <plat/dsp.h> +#include <plat/io.h> +#include "cm2_44xx.h" +#include "cm-regbits-44xx.h" + +#define OMAP4430_CM_M3_M3_CLKCTRL (OMAP4430_CM2_BASE + OMAP4430_CM2_CORE_INST \ + + OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET) + +static struct omap_rproc_timers_info ipu_timers[] = { + { .id = 3 }, + { .id = 4 }, +#ifdef CONFIG_REMOTEPROC_WATCHDOG + { .id = 9 }, + { .id = 11 }, +#endif +}; + +static struct omap_rproc_pdata omap4_rproc_data[] = { + { + .name = "dsp", + .iommu_name = "tesla", + .firmware = "tesla-dsp.bin", + .oh_name = "dsp_c0", + .clkdm_name = "dsp_clkdm", + }, + { + .name = "ipu", + .iommu_name = "ducati", + .firmware = "ducati-m3.bin", + .oh_name = "ipu_c0", + .oh_name_opt = "ipu_c1", + .clkdm_name = "ducati_clkdm", + .timers = ipu_timers, + .timers_cnt = ARRAY_SIZE(ipu_timers), + .idle_addr = OMAP4430_CM_M3_M3_CLKCTRL, + .idle_mask = OMAP4430_STBYST_MASK, + .suspend_addr = 0xb3bf02d8, + .suspend_mask = ~0, + .sus_timeout = 5000, + .sus_mbox_name = "mailbox-1", + }, +}; + +static struct omap_device_pm_latency omap_rproc_latency[] = { + { + OMAP_RPROC_DEFAULT_PM_LATENCY, + }, +}; + +static struct rproc_mem_pool *omap_rproc_get_pool(const char *name) +{ + struct rproc_mem_pool *pool = NULL; + + /* check for ipu currently. dsp will be handled later */ + if (!strcmp("ipu", name)) { + phys_addr_t paddr1 = omap_ipu_get_mempool_base( + OMAP_RPROC_MEMPOOL_STATIC); + phys_addr_t paddr2 = omap_ipu_get_mempool_base( + OMAP_RPROC_MEMPOOL_DYNAMIC); + u32 len1 = omap_ipu_get_mempool_size(OMAP_RPROC_MEMPOOL_STATIC); + u32 len2 = omap_ipu_get_mempool_size(OMAP_RPROC_MEMPOOL_DYNAMIC); + + if (!paddr1 && !paddr2) { + pr_err("no carveout memory available at all for " + "remotproc\n"); + return pool; + } + if (!paddr1 || !len1) + pr_warn("static memory is unavailable: 0x%x, 0x%x\n", + paddr1, len1); + if (!paddr2 || !len2) + pr_warn("carveout memory is unavailable: 0x%x, 0x%x\n", + paddr2, len2); + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (pool) { + pool->st_base = paddr1; + pool->st_size = len1; + pool->mem_base = paddr2; + pool->mem_size = len2; + pool->cur_base = paddr2; + pool->cur_size = len2; + } + } + + return pool; +} + +static int __init omap_rproc_init(void) +{ + const char *pdev_name = "omap-rproc"; + struct omap_hwmod *oh[2]; + struct omap_device *od; + int i, ret = 0, oh_count; + + /* names like ipu_cx/dsp_cx might show up on other OMAPs, too */ + if (!cpu_is_omap44xx()) + return 0; + + for (i = 0; i < ARRAY_SIZE(omap4_rproc_data); i++) { + const char *oh_name = omap4_rproc_data[i].oh_name; + const char *oh_name_opt = omap4_rproc_data[i].oh_name_opt; + oh_count = 0; + + oh[0] = omap_hwmod_lookup(oh_name); + if (!oh[0]) { + pr_err("could not look up %s\n", oh_name); + continue; + } + oh_count++; + + if (oh_name_opt) { + oh[1] = omap_hwmod_lookup(oh_name_opt); + if (!oh[1]) { + pr_err("could not look up %s\n", oh_name_opt); + continue; + } + oh_count++; + } + + omap4_rproc_data[i].memory_pool = + omap_rproc_get_pool(omap4_rproc_data[i].name); + od = omap_device_build_ss(pdev_name, i, oh, oh_count, + &omap4_rproc_data[i], + sizeof(struct omap_rproc_pdata), + omap_rproc_latency, + ARRAY_SIZE(omap_rproc_latency), + false); + if (IS_ERR(od)) { + pr_err("Could not build omap_device for %s:%s\n", + pdev_name, oh_name); + ret = PTR_ERR(od); + } + } + + return ret; +} +/* must be ready in time for device_initcall users */ +subsys_initcall(omap_rproc_init); diff --git a/arch/arm/mach-omap2/resetreason.c b/arch/arm/mach-omap2/resetreason.c new file mode 100644 index 0000000..316bfeb --- /dev/null +++ b/arch/arm/mach-omap2/resetreason.c @@ -0,0 +1,75 @@ +/* + * arch/arm/mach-omap2/resetreason.c + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/string.h> +#include "prm-regbits-44xx.h" +#include "prcm44xx.h" +#include "prm44xx.h" +#include "prminst44xx.h" +#include "resetreason.h" + +static char resetreason[1024]; + +static struct { + const char *str; + u32 mask; +} resetreason_flags[] = { + { "C2C ", OMAP4430_C2C_RST_MASK }, + { "IcePick ", OMAP4430_ICEPICK_RST_MASK }, + { "Voltage Manager ", OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK | + OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK | + OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK }, + { "external warm ", OMAP4430_EXTERNAL_WARM_RST_MASK }, + { "MPU Watchdog Timer ", OMAP4430_MPU_WDT_RST_MASK }, + { "warm software ", OMAP4430_GLOBAL_WARM_SW_RST_MASK }, + { "cold ", OMAP4430_GLOBAL_COLD_RST_MASK }, +}; + +const char *omap4_get_resetreason(void) +{ + return resetreason; +} + +static int __init resetreason_init(void) +{ + int i; + u32 reasons = + omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, + OMAP4_PRM_RSTST_OFFSET); + char buf[128]; + + strlcpy(resetreason, "Last reset was ", sizeof(resetreason)); + + for (i = 0; i < ARRAY_SIZE(resetreason_flags); i++) + if (reasons & resetreason_flags[i].mask) + strlcat(resetreason, resetreason_flags[i].str, + sizeof(resetreason)); + + snprintf(buf, sizeof(buf), "reset (PRM_RSTST=0x%x)\n", reasons); + + strlcat(resetreason, buf, sizeof(resetreason)); + + pr_info("%s\n", resetreason); + + omap4_prminst_write_inst_reg(reasons, OMAP4430_PRM_PARTITION, + OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_RSTST_OFFSET); + + return 0; +} + +postcore_initcall(resetreason_init); diff --git a/arch/arm/mach-omap2/resetreason.h b/arch/arm/mach-omap2/resetreason.h new file mode 100644 index 0000000..96c9a00 --- /dev/null +++ b/arch/arm/mach-omap2/resetreason.h @@ -0,0 +1,22 @@ +/* + * arch/arm/mach-omap2/resetreason.h + * + * Copyright (C) 2011 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MACH_OMAP2_RESETREASON_H_ +#define _MACH_OMAP2_RESETREASON_H_ + +const char *omap4_get_resetreason(void); + +#endif diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 1ac361b..76b9cfb 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -19,26 +19,20 @@ */ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/serial_reg.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/serial_8250.h> #include <linux/pm_runtime.h> -#include <linux/console.h> -#ifdef CONFIG_SERIAL_OMAP #include <plat/omap-serial.h> -#endif - #include <plat/common.h> #include <plat/board.h> #include <plat/clock.h> #include <plat/dma.h> -#include <plat/omap_hwmod.h> #include <plat/omap_device.h> +#include <plat/omap-pm.h> #include "prm2xxx_3xxx.h" #include "pm.h" @@ -47,65 +41,19 @@ #include "control.h" #include "mux.h" -#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV 0x52 -#define UART_OMAP_WER 0x17 /* Wake-up enable register */ - -#define UART_ERRATA_FIFO_FULL_ABORT (0x1 << 0) -#define UART_ERRATA_i202_MDR1_ACCESS (0x1 << 1) - -/* - * NOTE: By default the serial timeout is disabled as it causes lost characters - * over the serial ports. This means that the UART clocks will stay on until - * disabled via sysfs. This also causes that any deeper omap sleep states are - * blocked. - */ -#define DEFAULT_TIMEOUT 0 - #define MAX_UART_HWMOD_NAME_LEN 16 -struct omap_uart_state { - int num; - int can_sleep; - struct timer_list timer; - u32 timeout; - - void __iomem *wk_st; - void __iomem *wk_en; - u32 wk_mask; - u32 padconf; - u32 dma_enabled; - - struct clk *ick; - struct clk *fck; - int clocked; - - int irq; - int regshift; - int irqflags; - void __iomem *membase; - resource_size_t mapbase; - - struct list_head node; - struct omap_hwmod *oh; - struct platform_device *pdev; - - u32 errata; -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) - int context_valid; - - /* Registers to be saved/restored for OFF-mode */ - u16 dll; - u16 dlh; - u16 ier; - u16 sysc; - u16 scr; - u16 wer; - u16 mcr; -#endif -}; +static int omap_uart_con_id __initdata = -1; -static LIST_HEAD(uart_list); -static u8 num_uarts; +static struct omap_uart_port_info omap_serial_default_info[] = { + { + .use_dma = 0, + .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE, + .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, + .auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY, + }, +}; static int uart_idle_hwmod(struct omap_device *od) { @@ -129,396 +77,203 @@ static struct omap_device_pm_latency omap_uart_latency[] = { }, }; -static inline unsigned int __serial_read_reg(struct uart_port *up, - int offset) -{ - offset <<= up->regshift; - return (unsigned int)__raw_readb(up->membase + offset); -} - -static inline unsigned int serial_read_reg(struct omap_uart_state *uart, - int offset) -{ - offset <<= uart->regshift; - return (unsigned int)__raw_readb(uart->membase + offset); -} - -static inline void __serial_write_reg(struct uart_port *up, int offset, - int value) -{ - offset <<= up->regshift; - __raw_writeb(value, up->membase + offset); -} - -static inline void serial_write_reg(struct omap_uart_state *uart, int offset, - int value) -{ - offset <<= uart->regshift; - __raw_writeb(value, uart->membase + offset); -} - -/* - * Internal UARTs need to be initialized for the 8250 autoconfig to work - * properly. Note that the TX watermark initialization may not be needed - * once the 8250.c watermark handling code is merged. - */ - -static inline void __init omap_uart_reset(struct omap_uart_state *uart) -{ - serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); - serial_write_reg(uart, UART_OMAP_SCR, 0x08); - serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE); -} - -#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) - -/* - * Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6) - * The access to uart register after MDR1 Access - * causes UART to corrupt data. - * - * Need a delay = - * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) - * give 10 times as much - */ -static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val, - u8 fcr_val) -{ - u8 timeout = 255; - - serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val); - udelay(2); - serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT | - UART_FCR_CLEAR_RCVR); - /* - * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and - * TX_FIFO_E bit is 1. - */ - while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) & - (UART_LSR_THRE | UART_LSR_DR))) { - timeout--; - if (!timeout) { - /* Should *never* happen. we warn and carry on */ - dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n", - serial_read_reg(uart, UART_LSR)); - break; - } - udelay(1); - } -} - -static void omap_uart_save_context(struct omap_uart_state *uart) -{ - u16 lcr = 0; - - if (!enable_off_mode) - return; - - lcr = serial_read_reg(uart, UART_LCR); - serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B); - uart->dll = serial_read_reg(uart, UART_DLL); - uart->dlh = serial_read_reg(uart, UART_DLM); - serial_write_reg(uart, UART_LCR, lcr); - uart->ier = serial_read_reg(uart, UART_IER); - uart->sysc = serial_read_reg(uart, UART_OMAP_SYSC); - uart->scr = serial_read_reg(uart, UART_OMAP_SCR); - uart->wer = serial_read_reg(uart, UART_OMAP_WER); - serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_A); - uart->mcr = serial_read_reg(uart, UART_MCR); - serial_write_reg(uart, UART_LCR, lcr); - - uart->context_valid = 1; -} - -static void omap_uart_restore_context(struct omap_uart_state *uart) -{ - u16 efr = 0; +#ifdef CONFIG_OMAP_MUX +static struct omap_device_pad default_uart1_pads[] __initdata = { + { + .name = "uart1_cts.uart1_cts", + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, + { + .name = "uart1_rts.uart1_rts", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart1_tx.uart1_tx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart1_rx.uart1_rx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + .idle = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, +}; - if (!enable_off_mode) - return; +static struct omap_device_pad default_uart2_pads[] __initdata = { + { + .name = "uart2_cts.uart2_cts", + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, + { + .name = "uart2_rts.uart2_rts", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart2_tx.uart2_tx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart2_rx.uart2_rx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + .idle = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, +}; - if (!uart->context_valid) - return; +static struct omap_device_pad default_uart3_pads[] __initdata = { + { + .name = "uart3_cts_rctx.uart3_cts_rctx", + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, + { + .name = "uart3_rts_sd.uart3_rts_sd", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart3_tx_irtx.uart3_tx_irtx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart3_rx_irrx.uart3_rx_irrx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE0, + .idle = OMAP_PIN_INPUT | OMAP_MUX_MODE0, + }, +}; - uart->context_valid = 0; +static struct omap_device_pad default_omap36xx_uart4_pads[] __initdata = { + { + .name = "gpmc_wait2.uart4_tx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "gpmc_wait3.uart4_rx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE2, + .idle = OMAP_PIN_INPUT | OMAP_MUX_MODE2, + }, +}; - if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS) - omap_uart_mdr1_errataset(uart, UART_OMAP_MDR1_DISABLE, 0xA0); - else - serial_write_reg(uart, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); - - serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B); - efr = serial_read_reg(uart, UART_EFR); - serial_write_reg(uart, UART_EFR, UART_EFR_ECB); - serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */ - serial_write_reg(uart, UART_IER, 0x0); - serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B); - serial_write_reg(uart, UART_DLL, uart->dll); - serial_write_reg(uart, UART_DLM, uart->dlh); - serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */ - serial_write_reg(uart, UART_IER, uart->ier); - serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_A); - serial_write_reg(uart, UART_MCR, uart->mcr); - serial_write_reg(uart, UART_LCR, UART_LCR_CONF_MODE_B); - serial_write_reg(uart, UART_EFR, efr); - serial_write_reg(uart, UART_LCR, UART_LCR_WLEN8); - serial_write_reg(uart, UART_OMAP_SCR, uart->scr); - serial_write_reg(uart, UART_OMAP_WER, uart->wer); - serial_write_reg(uart, UART_OMAP_SYSC, uart->sysc); - - if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS) - omap_uart_mdr1_errataset(uart, UART_OMAP_MDR1_16X_MODE, 0xA1); - else - /* UART 16x mode */ - serial_write_reg(uart, UART_OMAP_MDR1, - UART_OMAP_MDR1_16X_MODE); -} +static struct omap_device_pad default_omap4_uart4_pads[] __initdata = { + { + .name = "uart4_tx.uart4_tx", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0, + }, + { + .name = "uart4_rx.uart4_rx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE0, + .idle = OMAP_PIN_INPUT | OMAP_MUX_MODE0, + }, +}; #else -static inline void omap_uart_save_context(struct omap_uart_state *uart) {} -static inline void omap_uart_restore_context(struct omap_uart_state *uart) {} -#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */ - -static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) -{ - if (uart->clocked) - return; - - omap_device_enable(uart->pdev); - uart->clocked = 1; - omap_uart_restore_context(uart); -} - -#ifdef CONFIG_PM - -static inline void omap_uart_disable_clocks(struct omap_uart_state *uart) -{ - if (!uart->clocked) - return; - - omap_uart_save_context(uart); - uart->clocked = 0; - omap_device_idle(uart->pdev); -} - -static void omap_uart_enable_wakeup(struct omap_uart_state *uart) -{ - /* Set wake-enable bit */ - if (uart->wk_en && uart->wk_mask) { - u32 v = __raw_readl(uart->wk_en); - v |= uart->wk_mask; - __raw_writel(v, uart->wk_en); - } - - /* Ensure IOPAD wake-enables are set */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 v = omap_ctrl_readw(uart->padconf); - v |= OMAP3_PADCONF_WAKEUPENABLE0; - omap_ctrl_writew(v, uart->padconf); - } -} - -static void omap_uart_disable_wakeup(struct omap_uart_state *uart) -{ - /* Clear wake-enable bit */ - if (uart->wk_en && uart->wk_mask) { - u32 v = __raw_readl(uart->wk_en); - v &= ~uart->wk_mask; - __raw_writel(v, uart->wk_en); - } - - /* Ensure IOPAD wake-enables are cleared */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 v = omap_ctrl_readw(uart->padconf); - v &= ~OMAP3_PADCONF_WAKEUPENABLE0; - omap_ctrl_writew(v, uart->padconf); - } -} - -static void omap_uart_smart_idle_enable(struct omap_uart_state *uart, - int enable) -{ - u8 idlemode; - - if (enable) { - /** - * Errata 2.15: [UART]:Cannot Acknowledge Idle Requests - * in Smartidle Mode When Configured for DMA Operations. - */ - if (uart->dma_enabled) - idlemode = HWMOD_IDLEMODE_FORCE; - else - idlemode = HWMOD_IDLEMODE_SMART; - } else { - idlemode = HWMOD_IDLEMODE_NO; - } - - omap_hwmod_set_slave_idlemode(uart->oh, idlemode); -} - -static void omap_uart_block_sleep(struct omap_uart_state *uart) -{ - omap_uart_enable_clocks(uart); - - omap_uart_smart_idle_enable(uart, 0); - uart->can_sleep = 0; - if (uart->timeout) - mod_timer(&uart->timer, jiffies + uart->timeout); - else - del_timer(&uart->timer); -} - -static void omap_uart_allow_sleep(struct omap_uart_state *uart) -{ - if (device_may_wakeup(&uart->pdev->dev)) - omap_uart_enable_wakeup(uart); - else - omap_uart_disable_wakeup(uart); - - if (!uart->clocked) - return; - - omap_uart_smart_idle_enable(uart, 1); - uart->can_sleep = 1; - del_timer(&uart->timer); -} - -static void omap_uart_idle_timer(unsigned long data) -{ - struct omap_uart_state *uart = (struct omap_uart_state *)data; - - omap_uart_allow_sleep(uart); -} - -void omap_uart_prepare_idle(int num) -{ - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - if (num == uart->num && uart->can_sleep) { - omap_uart_disable_clocks(uart); - return; - } - } -} - -void omap_uart_resume_idle(int num) -{ - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - if (num == uart->num && uart->can_sleep) { - omap_uart_enable_clocks(uart); - - /* Check for IO pad wakeup */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 p = omap_ctrl_readw(uart->padconf); - - if (p & OMAP3_PADCONF_WAKEUPEVENT0) - omap_uart_block_sleep(uart); - } +static struct omap_device_pad default_uart1_pads[] __initdata = {}; +static struct omap_device_pad default_uart2_pads[] __initdata = {}; +static struct omap_device_pad default_uart3_pads[] __initdata = {}; +static struct omap_device_pad default_omap36xx_uart4_pads[] __initdata = {}; +static struct omap_device_pad default_omap4_uart4_pads[] __initdata = {}; +#endif - /* Check for normal UART wakeup */ - if (__raw_readl(uart->wk_st) & uart->wk_mask) - omap_uart_block_sleep(uart); - return; +static __init void omap_serial_fill_default_pads(struct omap_board_data *bdata) +{ + BUG_ON(!cpu_is_omap44xx() && !cpu_is_omap34xx()); + + switch (bdata->id) { + case 0: + bdata->pads = default_uart1_pads; + bdata->pads_cnt = ARRAY_SIZE(default_uart1_pads); + break; + case 1: + bdata->pads = default_uart2_pads; + bdata->pads_cnt = ARRAY_SIZE(default_uart2_pads); + break; + case 2: + bdata->pads = default_uart3_pads; + bdata->pads_cnt = ARRAY_SIZE(default_uart3_pads); + break; + case 3: + if (cpu_is_omap44xx()) { + bdata->pads = default_omap4_uart4_pads; + bdata->pads_cnt = + ARRAY_SIZE(default_omap4_uart4_pads); + } else { + bdata->pads = default_omap36xx_uart4_pads; + bdata->pads_cnt = + ARRAY_SIZE(default_omap36xx_uart4_pads); } + break; + default: + break; } } -void omap_uart_prepare_suspend(void) -{ - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - omap_uart_allow_sleep(uart); - } -} - -int omap_uart_can_sleep(void) +/* TBD: Will be removed once we have irq-chaing mechanism */ +static bool omap_uart_chk_wakeup(struct platform_device *pdev) { - struct omap_uart_state *uart; - int can_sleep = 1; - - list_for_each_entry(uart, &uart_list, node) { - if (!uart->clocked) - continue; - - if (!uart->can_sleep) { - can_sleep = 0; - continue; + struct omap_uart_port_info *up = pdev->dev.platform_data; + struct omap_device *od; + u32 wkst = 0; + bool ret = false; + + od = to_omap_device(pdev); + if (omap_hwmod_pad_get_wakeup_status(od->hwmods[0])) + ret = true; + + if (up->wk_st && up->wk_en && up->wk_mask) { + /* Check for normal UART wakeup (and clear it) */ + wkst = __raw_readl(up->wk_st) & up->wk_mask; + if (wkst) { + __raw_writel(wkst, up->wk_st); + ret = true; } - - /* This UART can now safely sleep. */ - omap_uart_allow_sleep(uart); } - return can_sleep; + return ret; } -/** - * omap_uart_interrupt() - * - * This handler is used only to detect that *any* UART interrupt has - * occurred. It does _nothing_ to handle the interrupt. Rather, - * any UART interrupt will trigger the inactivity timer so the - * UART will not idle or sleep for its timeout period. - * - **/ -/* static int first_interrupt; */ -static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) +static void omap_uart_wakeup_enable(struct platform_device *pdev, bool enable) { - struct omap_uart_state *uart = dev_id; - - omap_uart_block_sleep(uart); + struct omap_device *od; - return IRQ_NONE; + od = to_omap_device(pdev); + if (enable) + omap_hwmod_enable_wakeup(od->hwmods[0]); + else + omap_hwmod_disable_wakeup(od->hwmods[0]); } -static void omap_uart_idle_init(struct omap_uart_state *uart) +static void omap_uart_idle_init(struct omap_uart_port_info *uart, + unsigned short num) { - int ret; - - uart->can_sleep = 0; - uart->timeout = DEFAULT_TIMEOUT; - setup_timer(&uart->timer, omap_uart_idle_timer, - (unsigned long) uart); - if (uart->timeout) - mod_timer(&uart->timer, jiffies + uart->timeout); - omap_uart_smart_idle_enable(uart, 0); - - if (cpu_is_omap34xx() && !cpu_is_ti816x()) { - u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD; + if (cpu_is_omap44xx()) { + uart->wer |= OMAP4_UART_WER_MOD_WKUP; + } else if (cpu_is_omap34xx()) { + u32 mod = num > 1 ? OMAP3430_PER_MOD : CORE_MOD; u32 wk_mask = 0; - u32 padconf = 0; - /* XXX These PRM accesses do not belong here */ + uart->wer |= OMAP2_UART_WER_MOD_WKUP; uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1); uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1); - switch (uart->num) { + switch (num) { case 0: wk_mask = OMAP3430_ST_UART1_MASK; - padconf = 0x182; break; case 1: wk_mask = OMAP3430_ST_UART2_MASK; - padconf = 0x17a; break; case 2: wk_mask = OMAP3430_ST_UART3_MASK; - padconf = 0x19e; break; case 3: wk_mask = OMAP3630_ST_UART4_MASK; - padconf = 0x0d2; break; } uart->wk_mask = wk_mask; - uart->padconf = padconf; } else if (cpu_is_omap24xx()) { u32 wk_mask = 0; u32 wk_en = PM_WKEN1, wk_st = PM_WKST1; - switch (uart->num) { + switch (num) { case 0: wk_mask = OMAP24XX_ST_UART1_MASK; break; @@ -543,162 +298,87 @@ static void omap_uart_idle_init(struct omap_uart_state *uart) uart->wk_en = NULL; uart->wk_st = NULL; uart->wk_mask = 0; - uart->padconf = 0; - } - - uart->irqflags |= IRQF_SHARED; - ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt, - IRQF_SHARED, "serial idle", (void *)uart); - WARN_ON(ret); -} - -void omap_uart_enable_irqs(int enable) -{ - int ret; - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - if (enable) { - pm_runtime_put_sync(&uart->pdev->dev); - ret = request_threaded_irq(uart->irq, NULL, - omap_uart_interrupt, - IRQF_SHARED, - "serial idle", - (void *)uart); - } else { - pm_runtime_get_noresume(&uart->pdev->dev); - free_irq(uart->irq, (void *)uart); - } } } -static ssize_t sleep_timeout_show(struct device *dev, - struct device_attribute *attr, - char *buf) +char *cmdline_find_option(char *str) { - struct platform_device *pdev = to_platform_device(dev); - struct omap_device *odev = to_omap_device(pdev); - struct omap_uart_state *uart = odev->hwmods[0]->dev_attr; + extern char *saved_command_line; - return sprintf(buf, "%u\n", uart->timeout / HZ); + return strstr(saved_command_line, str); } -static ssize_t sleep_timeout_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t n) +struct omap_hwmod *omap_uart_hwmod_lookup(int num) { - struct platform_device *pdev = to_platform_device(dev); - struct omap_device *odev = to_omap_device(pdev); - struct omap_uart_state *uart = odev->hwmods[0]->dev_attr; - unsigned int value; - - if (sscanf(buf, "%u", &value) != 1) { - dev_err(dev, "sleep_timeout_store: Invalid value\n"); - return -EINVAL; - } - - uart->timeout = value * HZ; - if (uart->timeout) - mod_timer(&uart->timer, jiffies + uart->timeout); - else - /* A zero value means disable timeout feature */ - omap_uart_block_sleep(uart); - - return n; -} + struct omap_hwmod *oh; + char oh_name[MAX_UART_HWMOD_NAME_LEN]; -static DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show, - sleep_timeout_store); -#define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr)) -#else -static inline void omap_uart_idle_init(struct omap_uart_state *uart) {} -static void omap_uart_block_sleep(struct omap_uart_state *uart) -{ - /* Needed to enable UART clocks when built without CONFIG_PM */ - omap_uart_enable_clocks(uart); + snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, "uart%d", num + 1); + oh = omap_hwmod_lookup(oh_name); + WARN(IS_ERR(oh), "Could not lookup hmwod info for %s\n", + oh_name); + return oh; } -#define DEV_CREATE_FILE(dev, attr) -#endif /* CONFIG_PM */ -#ifndef CONFIG_SERIAL_OMAP -/* - * Override the default 8250 read handler: mem_serial_in() - * Empty RX fifo read causes an abort on omap3630 and omap4 - * This function makes sure that an empty rx fifo is not read on these silicons - * (OMAP1/2/3430 are not affected) - */ -static unsigned int serial_in_override(struct uart_port *up, int offset) +void omap_rts_mux_write(u16 val, int num) { - if (UART_RX == offset) { - unsigned int lsr; - lsr = __serial_read_reg(up, UART_LSR); - if (!(lsr & UART_LSR_DR)) - return -EPERM; - } - - return __serial_read_reg(up, offset); -} + struct omap_hwmod *oh; + int i; -static void serial_out_override(struct uart_port *up, int offset, int value) -{ - unsigned int status, tmout = 10000; + oh = omap_uart_hwmod_lookup(num); + if (!oh) + return; - status = __serial_read_reg(up, UART_LSR); - while (!(status & UART_LSR_THRE)) { - /* Wait up to 10ms for the character(s) to be sent. */ - if (--tmout == 0) + for (i = 0; i < oh->mux->nr_pads ; i++) { + if (strstr(oh->mux->pads[i].name, "rts")) { + omap_mux_write(oh->mux->pads[i].partition, + val, + oh->mux->pads[i].mux[0].reg_offset); break; - udelay(1); - status = __serial_read_reg(up, UART_LSR); + } } - __serial_write_reg(up, offset, value); } -#endif static int __init omap_serial_early_init(void) { int i = 0; + char omap_tty_name[MAX_UART_HWMOD_NAME_LEN]; + struct omap_hwmod *oh; - do { - char oh_name[MAX_UART_HWMOD_NAME_LEN]; - struct omap_hwmod *oh; - struct omap_uart_state *uart; - - snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, - "uart%d", i + 1); - oh = omap_hwmod_lookup(oh_name); - if (!oh) - break; - - uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL); - if (WARN_ON(!uart)) - return -ENODEV; + for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) { + snprintf(omap_tty_name, MAX_UART_HWMOD_NAME_LEN, + "%s%d", OMAP_SERIAL_NAME, i); + if (cmdline_find_option(omap_tty_name)) { + omap_uart_con_id = i; + oh = omap_uart_hwmod_lookup(i); + oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET; + return 0; + } + } + return 0; +} +core_initcall(omap_serial_early_init); - uart->oh = oh; - uart->num = i++; - list_add_tail(&uart->node, &uart_list); - num_uarts++; +void __init omap_serial_init_port_pads(int id, struct omap_device_pad *pads, + int size, struct omap_uart_port_info *info) +{ + struct omap_board_data bdata; - /* - * NOTE: omap_hwmod_setup*() has not yet been called, - * so no hwmod functions will work yet. - */ + bdata.id = id; + bdata.flags = 0; + bdata.pads = pads; + bdata.pads_cnt = size; - /* - * During UART early init, device need to be probed - * to determine SoC specific init before omap_device - * is ready. Therefore, don't allow idle here - */ - uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET; - } while (1); + if (!bdata.pads) + omap_serial_fill_default_pads(&bdata); - return 0; + omap_serial_init_port(&bdata, info); } -core_initcall(omap_serial_early_init); /** * omap_serial_init_port() - initialize single serial port * @bdata: port specific board data pointer + * @info: platform specific data pointer * * This function initialies serial driver for given port only. * Platforms can call this function instead of omap_serial_init() @@ -707,171 +387,114 @@ core_initcall(omap_serial_early_init); * Don't mix calls to omap_serial_init_port() and omap_serial_init(), * use only one of the two. */ -void __init omap_serial_init_port(struct omap_board_data *bdata) +void __init omap_serial_init_port(struct omap_board_data *bdata, + struct omap_uart_port_info *info) { - struct omap_uart_state *uart; struct omap_hwmod *oh; struct omap_device *od; - void *pdata = NULL; - u32 pdata_size = 0; - char *name; -#ifndef CONFIG_SERIAL_OMAP - struct plat_serial8250_port ports[2] = { - {}, - {.flags = 0}, - }; - struct plat_serial8250_port *p = &ports[0]; -#else - struct omap_uart_port_info omap_up; -#endif + struct omap_uart_port_info *pdata; + char *name = DRIVER_NAME; if (WARN_ON(!bdata)) return; if (WARN_ON(bdata->id < 0)) return; - if (WARN_ON(bdata->id >= num_uarts)) + if (WARN_ON(bdata->id >= OMAP_MAX_HSUART_PORTS)) return; - list_for_each_entry(uart, &uart_list, node) - if (bdata->id == uart->num) - break; - - oh = uart->oh; - uart->dma_enabled = 0; -#ifndef CONFIG_SERIAL_OMAP - name = "serial8250"; - - /* - * !! 8250 driver does not use standard IORESOURCE* It - * has it's own custom pdata that can be taken from - * the hwmod resource data. But, this needs to be - * done after the build. - * - * ?? does it have to be done before the register ?? - * YES, because platform_device_data_add() copies - * pdata, it does not use a pointer. - */ - p->flags = UPF_BOOT_AUTOCONF; - p->iotype = UPIO_MEM; - p->regshift = 2; - p->uartclk = OMAP24XX_BASE_BAUD * 16; - p->irq = oh->mpu_irqs[0].irq; - p->mapbase = oh->slaves[0]->addr->pa_start; - p->membase = omap_hwmod_get_mpu_rt_va(oh); - p->irqflags = IRQF_SHARED; - p->private_data = uart; - - /* - * omap44xx, ti816x: Never read empty UART fifo - * omap3xxx: Never read empty UART fifo on UARTs - * with IP rev >=0x52 - */ - uart->regshift = p->regshift; - uart->membase = p->membase; - if (cpu_is_omap44xx() || cpu_is_ti816x()) - uart->errata |= UART_ERRATA_FIFO_FULL_ABORT; - else if ((serial_read_reg(uart, UART_OMAP_MVER) & 0xFF) - >= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV) - uart->errata |= UART_ERRATA_FIFO_FULL_ABORT; - - if (uart->errata & UART_ERRATA_FIFO_FULL_ABORT) { - p->serial_in = serial_in_override; - p->serial_out = serial_out_override; - } - - pdata = &ports[0]; - pdata_size = 2 * sizeof(struct plat_serial8250_port); -#else + oh = omap_uart_hwmod_lookup(bdata->id); + if (!oh) + return; - name = DRIVER_NAME; + if (info == NULL) + info = omap_serial_default_info; - omap_up.dma_enabled = uart->dma_enabled; - omap_up.uartclk = OMAP24XX_BASE_BAUD * 16; - omap_up.mapbase = oh->slaves[0]->addr->pa_start; - omap_up.membase = omap_hwmod_get_mpu_rt_va(oh); - omap_up.irqflags = IRQF_SHARED; - omap_up.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + pr_err("Memory allocation for UART pdata failed\n"); + return; + } - pdata = &omap_up; - pdata_size = sizeof(struct omap_uart_port_info); + if (cpu_is_omap34xx() || cpu_is_omap44xx()) + pdata->errata |= UART_ERRATA_i202_MDR1_ACCESS; + + omap_uart_idle_init(pdata, bdata->id); + + pdata->uartclk = OMAP24XX_BASE_BAUD * 16; + pdata->flags = UPF_BOOT_AUTOCONF; + pdata->enable_wakeup = omap_uart_wakeup_enable; + pdata->use_dma = info->use_dma; + pdata->chk_wakeup = omap_uart_chk_wakeup; + pdata->dma_rx_buf_size = info->dma_rx_buf_size; + pdata->dma_rx_poll_rate = info->dma_rx_poll_rate; + pdata->dma_rx_timeout = info->dma_rx_timeout; + pdata->auto_sus_timeout = info->auto_sus_timeout; + pdata->wake_peer = info->wake_peer; + pdata->rts_mux_driver_control = info->rts_mux_driver_control; + if (bdata->id == omap_uart_con_id) { + pdata->console_uart = true; +#ifdef CONFIG_DEBUG_LL + pdata->auto_sus_timeout = -1; #endif + } - if (WARN_ON(!oh)) - return; + if (pdata->use_dma && + cpu_is_omap44xx() && omap_rev() > OMAP4430_REV_ES1_0) + pdata->errata |= OMAP4_UART_ERRATA_i659_TX_THR; - od = omap_device_build(name, uart->num, oh, pdata, pdata_size, - omap_uart_latency, - ARRAY_SIZE(omap_uart_latency), false); + od = omap_device_build(name, bdata->id, oh, pdata, + sizeof(*pdata), omap_uart_latency, + ARRAY_SIZE(omap_uart_latency), false); WARN(IS_ERR(od), "Could not build omap_device for %s: %s.\n", name, oh->name); oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt); - uart->irq = oh->mpu_irqs[0].irq; - uart->regshift = 2; - uart->mapbase = oh->slaves[0]->addr->pa_start; - uart->membase = omap_hwmod_get_mpu_rt_va(oh); - uart->pdev = &od->pdev; - - oh->dev_attr = uart; - - console_lock(); /* in case the earlycon is on the UART */ - - /* - * Because of early UART probing, UART did not get idled - * on init. Now that omap_device is ready, ensure full idle - * before doing omap_device_enable(). - */ - omap_hwmod_idle(uart->oh); - - omap_device_enable(uart->pdev); - omap_uart_idle_init(uart); - omap_uart_reset(uart); - omap_hwmod_enable_wakeup(uart->oh); - omap_device_idle(uart->pdev); - - /* - * Need to block sleep long enough for interrupt driven - * driver to start. Console driver is in polling mode - * so device needs to be kept enabled while polling driver - * is in use. - */ - if (uart->timeout) - uart->timeout = (30 * HZ); - omap_uart_block_sleep(uart); - uart->timeout = DEFAULT_TIMEOUT; - - console_unlock(); - - if ((cpu_is_omap34xx() && uart->padconf) || - (uart->wk_en && uart->wk_mask)) { + if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads) || + (pdata->wk_en && pdata->wk_mask)) { device_init_wakeup(&od->pdev.dev, true); - DEV_CREATE_FILE(&od->pdev.dev, &dev_attr_sleep_timeout); } - /* Enable the MDR1 errata for OMAP3 */ - if (cpu_is_omap34xx() && !cpu_is_ti816x()) - uart->errata |= UART_ERRATA_i202_MDR1_ACCESS; + kfree(pdata); } /** - * omap_serial_init() - initialize all supported serial ports + * omap_serial_board_init() - initialize all supported serial ports + * @platform_data: platform specific data pointer * * Initializes all available UARTs as serial ports. Platforms * can call this function when they want to have default behaviour * for serial ports (e.g initialize them all as serial ports). */ -void __init omap_serial_init(void) +void __init omap_serial_board_init(struct omap_uart_port_info *platform_data) { - struct omap_uart_state *uart; struct omap_board_data bdata; + u8 i; - list_for_each_entry(uart, &uart_list, node) { - bdata.id = uart->num; + for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) { + bdata.id = i; bdata.flags = 0; bdata.pads = NULL; bdata.pads_cnt = 0; - omap_serial_init_port(&bdata); + if (cpu_is_omap44xx() || cpu_is_omap34xx()) + omap_serial_fill_default_pads(&bdata); + + if (platform_data == NULL) + omap_serial_init_port(&bdata, NULL); + else + omap_serial_init_port(&bdata, &platform_data[i]); } } + +/** + * omap_serial_init() - initialize all supported serial ports + * + * Initializes all available UARTs. + * Platforms can call this function when they want to have default behaviour + * for serial ports (e.g initialize them all as serial ports). + */ +void __init omap_serial_init(void) +{ + omap_serial_board_init(NULL); +} diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S new file mode 100644 index 0000000..b025e5f --- /dev/null +++ b/arch/arm/mach-omap2/sleep44xx.S @@ -0,0 +1,695 @@ +/* + * OMAP44xx CPU low power powerdown and powerup code. + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Written by Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software,you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/linkage.h> +#include <asm/system.h> +#include <asm/smp_scu.h> +#include <asm/memory.h> +#include <asm/hardware/cache-l2x0.h> + +#include <plat/omap44xx.h> +#include <mach/omap4-common.h> + +#include "omap4-sar-layout.h" + +#ifdef CONFIG_SMP + +/* Masks used for MMU manipulation */ +#define TTRBIT_MASK 0xffffc000 +#define TABLE_INDEX_MASK 0xfff00000 +#define TABLE_ENTRY 0x00000c02 +#define CACHE_DISABLE_MASK 0xffffe7fb +#define TABLE_ADDRESS_OFFSET 0x04 +#define CR_VALUE_OFFSET 0x08 +#define SCU_POWER_SECURE_INDEX 0x108 + + +/* + * Macro to call PPA svc when MMU is OFF + * Caller must setup r0 and r3 before calling this macro + * @r0: PPA service ID + * @r3: Pointer to params +*/ +.macro LM_CALL_PPA_SERVICE_PA + mov r1, #0x0 @ Process ID + mov r2, #0x4 @ Flag + mov r6, #0xff + mov r12, #0x00 @ Secure Service ID + dsb + smc #0 +.endm + +/* + * To load POR which was saved in SAR RAM + */ +POR_params: +.word 1, 0 + + +ppa_zero_params: + .word 0x0 + +/* + * ============================= + * == CPU suspend entry point == + * ============================= + * + * void omap4_cpu_suspend(unsigned int cpu, unsigned int save_state) + * + * This function code saves the CPU context and performs the CPU + * power down sequence. Calling WFI effectively changes the CPU + * power domains states to the desired target power state. + * + * @cpu : contains cpu id (r0) + * @save_state : contains context save state (r1) + * 0 - No context lost + * 1 - CPUx L1 and logic lost: MPUSS CSWR + * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR + * 3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF + * @return: This function never returns for CPU OFF and DORMANT power states. + * Post WFI, CPU transitions to DORMANT or OFF power state and on wake-up + * from this follows a full CPU reset path via ROM code to CPU restore code. + * It returns to the caller for CPU INACTIVE and ON power states or in case + * CPU failed to transition to targeted OFF/DORMANT state. + */ + +ENTRY(omap4_cpu_suspend) + stmfd sp!, {r0-r12, lr} @ Save registers on stack + cmp r1, #0x0 + beq do_WFI @ Nothing to save, jump to WFI + mov r5, r0 + mov r6, r1 + bl omap4_get_sar_ram_base + mov r8, r0 + ands r5, r5, #0x0f + streq r6, [r8, #L2X0_SAVE_OFFSET0] @ Store save state + strne r6, [r8, #L2X0_SAVE_OFFSET1] + orreq r8, r8, #CPU0_SAVE_OFFSET + orrne r8, r8, #CPU1_SAVE_OFFSET + + /* + * Save only needed CPU CP15 registers. VFP, breakpoint, + * performance monitor registers are not saved. Generic + * code suppose to take care of those. + */ + mov r4, sp @ Store sp + mrs r5, spsr @ Store spsr + mov r6, lr @ Store lr + stmia r8!, {r4-r6} + + /* c1 and c2 registers */ + mrc p15, 0, r4, c1, c0, 2 @ CPACR + mrc p15, 0, r5, c2, c0, 0 @ TTBR0 + mrc p15, 0, r6, c2, c0, 1 @ TTBR1 + mrc p15, 0, r7, c2, c0, 2 @ TTBCR + stmia r8!, {r4-r7} + + /* c3 and c10 registers */ + mrc p15, 0, r4, c3, c0, 0 @ DACR + mrc p15, 0, r5, c10, c2, 0 @ PRRR + mrc p15, 0, r6, c10, c2, 1 @ NMRR + stmia r8!,{r4-r6} + + /* c12, c13 and CPSR registers */ + mrc p15, 0, r4, c13, c0, 1 @ Context ID + mrc p15, 0, r5, c13, c0, 2 @ User r/w thread ID + mrc p15, 0, r6, c12, c0, 0 @ Secure or NS VBAR + mrs r7, cpsr @ Store CPSR + stmia r8!, {r4-r7} + + /* c1 control register */ + mrc p15, 0, r4, c1, c0, 0 @ Save control register + stmia r8!, {r4} + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + bl v7_flush_dcache_all + + bl omap4_get_sar_ram_base + ldr r9, [r0, #OMAP_TYPE_OFFSET] + cmp r9, #0x1 @ Check for HS device + bne skip_secure_l1_flush + mov r0, #SCU_PM_NORMAL + mov r1, #0xFF @ clean seucre L1 + stmfd r13!, {r4-r12, r14} + ldr r12, =SCU_POWER_SECURE_INDEX + dsb + smc #0 + dsb + ldmfd r13!, {r4-r12, r14} +skip_secure_l1_flush: + + /* + * Clear the SCTLR.C bit to prevent further data cache + * allocation. Clearing SCTLR.C would make all the data accesses + * strongly ordered and would not hit the cache. + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #(1 << 2) @ Disable the C bit + mcr p15, 0, r0, c1, c0, 0 + isb + + /* + * Invalidate L1 data cache. Even though only invalidate is + * necessary exported flush API is used here. Doing clean + * on already clean cache would be almost NOP. + */ + bl v7_flush_dcache_all + + /* + * Switch the CPU from Symmetric Multiprocessing (SMP) mode + * to AsymmetricMultiprocessing (AMP) mode by programming + * the SCU power status to DORMANT or OFF mode. + * This enables the CPU to be taken out of coherency by + * preventing the CPU from receiving cache, TLB, or BTB + * maintenance operations broadcast by other CPUs in the cluster. + */ + bl omap4_get_sar_ram_base + mov r8, r0 + ldr r9, [r8, #OMAP_TYPE_OFFSET] + cmp r9, #0x1 @ Check for HS device + bne scu_gp_set + mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR + ands r0, r0, #0x0f + ldreq r0, [r8, #SCU_OFFSET0] + ldrne r0, [r8, #SCU_OFFSET1] + mov r1, #0x00 @ Secure L1 is clean already + stmfd r13!, {r4-r12, r14} + ldr r12, =SCU_POWER_SECURE_INDEX + dsb + smc #0 + dsb + ldmfd r13!, {r4-r12, r14} + b skip_scu_gp_set +scu_gp_set: + mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR + ands r0, r0, #0x0f + ldreq r1, [r8, #SCU_OFFSET0] + ldrne r1, [r8, #SCU_OFFSET1] + bl omap4_get_scu_base + bl scu_power_mode +skip_scu_gp_set: + isb + dsb + + mrc p15, 0, r0, c1, c1, 2 @Read NSACR data + tst r0, #(1 << 18) + mrcne p15, 0, r0, c1, c0, 1 + bicne r0, r0, #(1 << 6) + mcrne p15, 0, r0, c1, c0, 1 + isb + + +#ifdef CONFIG_CACHE_L2X0 + /* + * Clean and invalidate the L2 cache. + * Common cache-l2x0.c functions can't be used here since it + * uses spinlocks. We are out of coherency here with data cache + * disabled. The spinlock implementation uses exclusive load/store + * instruction which can fail without data cache being enabled. + * OMAP4 hardware doesn't support exclusive monitor which can + * overcome exclusive access issue. Because of this, CPU can + * lead to deadlock. + */ +l2x_clean_inv: + bl omap4_get_sar_ram_base + mov r8, r0 + mrc p15, 0, r5, c0, c0, 5 @ Read MPIDR + ands r5, r5, #0x0f + ldreq r0, [r8, #L2X0_SAVE_OFFSET0] + ldrne r0, [r8, #L2X0_SAVE_OFFSET1] + cmp r0, #3 + bne do_WFI +#ifdef CONFIG_PL310_ERRATA_727915 + mov r0, #0x03 + mov r12, #0x100 + dsb + smc #0 + dsb +#endif + bl omap4_get_l2cache_base + mov r2, r0 + ldr r0, =0xffff + str r0, [r2, #L2X0_CLEAN_INV_WAY] +wait: + ldr r0, [r2, #L2X0_CLEAN_INV_WAY] + ands r0, r0, #0xff + bne wait +#ifdef CONFIG_PL310_ERRATA_727915 + mov r0, #0x00 + mov r12, #0x100 + dsb + smc #0 + dsb +#endif +l2x_sync: + bl omap4_get_l2cache_base + mov r2, r0 + mov r0, #0x0 + str r0, [r2, #L2X0_CACHE_SYNC] +sync: + ldr r0, [r2, #L2X0_CACHE_SYNC] + ands r0, r0, #0x1 + bne sync +#endif + +do_WFI: + bl omap_do_wfi + + /* + * CPU is here when it failed to enter OFF/DORMANT or + * no low power state was attempted. + */ + mrc p15, 0, r0, c1, c0, 0 + tst r0, #(1 << 2) @ Check C bit enabled? + orreq r0, r0, #(1 << 2) @ Enable the C bit + mcreq p15, 0, r0, c1, c0, 0 + isb + + /* Enable SMP bit if it's being disabled */ + mrc p15, 0, r0, c1, c0, 1 + tst r0, #(1 << 6) @ Check SMP bit enabled? + orreq r0, r0, #(1 << 6) + mcreq p15, 0, r0, c1, c0, 1 + isb + + /* + * Ensure the CPU power state is set to NORMAL in + * SCU power state so that CPU is back in coherency. + * In non-coherent mode CPU can lock-up and lead to + * system deadlock. + */ + bl omap4_get_sar_ram_base + mov r8, r0 + ldr r9, [r8, #OMAP_TYPE_OFFSET] + cmp r9, #0x1 @ Check for HS device + bne scu_gp_clear + mov r0, #SCU_PM_NORMAL + mov r1, #0x00 + stmfd r13!, {r4-r12, r14} + ldr r12, =SCU_POWER_SECURE_INDEX + dsb + smc #0 + dsb + ldmfd r13!, {r4-r12, r14} + b skip_scu_gp_clear +scu_gp_clear: + bl omap4_get_scu_base + mov r1, #SCU_PM_NORMAL + bl scu_power_mode +skip_scu_gp_clear: + isb + dsb + + ldmfd sp!, {r0-r12, pc} @ Restore regs and return +ENDPROC(omap4_cpu_suspend) + +/* + * ============================ + * == CPU resume entry point == + * ============================ + * + * void omap4_cpu_resume(void) + * + * ROM code jumps to this function while waking up from CPU + * OFF or DORMANT state. Physical address of the function is + * stored in the SAR RAM while entering to OFF or DORMANT mode. + */ + +ENTRY(omap4_cpu_resume) + /* + * CPU1 must check if CPU0 is alive/awaken. + * if PL310 is OFF, MPUSS was OFF and CPU0 is still off, + * CPU1 must go to sleep and wait for CPU0. + * CPU0 is needed for any PPA API to work. + */ + mrc p15, 0, r0, c0, c0, 5 @ Get cpuID + ands r0, r0, #0x0f @ Continue boot if CPU0 + beq continue_boot + ldr r8, =OMAP44XX_SAR_RAM_BASE + ldr r9, [r8, #OMAP_TYPE_OFFSET] + cmp r9, #0x1 @ Check for HS device + bne continue_boot @ Continue on GP devcies + ldr r2, =OMAP44XX_L2CACHE_BASE + ldr r0, [r2, #L2X0_CTRL] + and r0, #0x0f + cmp r0, #1 @ is CPU0 already UP? + beq ppa_cp15_cpu1_configure @ CPU1 HS go to next stage + /* + * When CPU1 is released to control of HLOS in the case of OSWR + * and OFF mode, PPA below v1.7.3[1] is not performing all + * Memory coherency and TLB operations required. + * + * A WA to recover cleanly from this scenario is to switch CPU1 back to + * previous OFF state. This forces a reset of CPU1, which in turn + * forces CPU1 not to override MMU descriptors already in place in + * internal RAM setup by CPU0. CPU1 will also sync to the in-place + * descriptors on the next wakeup. CPU1 wakeup is done by + * later kernel subsystems depending on suspend or cpuidle path + * being exercised. + * NOTE - for OSWR, state provided is 2, and for OFF, state is 3, + * Since the bug impacts OFF and OSWR, we need to force a 0x3 to + * shut off CPU1 + * + * Since many distributions may not be able to update PPA OR would like + * to support platforms with older PPA, we provide a config option. + * This is simpler and makes the current code remain cleaner in + * comparison to a flag based handling in CPU1 recovery for + * board + PPA revision combinations. + * + * Having this config option enabled even on platforms with fixed PPA + * should not impact stability, however, ability to make CPU1 available + * for operations a little earlier is curtailed. + * + * Foot note [1]: + * v1.7.3 is the official TI PPA version. Custom PPA could have + * the relevant changes ported over to it. + */ +#ifdef CONFIG_OMAP4_PPA_CPU1_ONLINE_BUG + mov r0, #0x03 @ target CPU1 to OFF(mpusspd=OSWR/OFF) + mov r1, #0x00 @ Secure L1 is already clean + ldr r12, =SCU_POWER_SECURE_INDEX + dsb + smc #0 + + isb @ Necessary barriers before wfi + dsb + dmb + wfi @ wait for interrupt + nop + nop + + /* + * IF we came out of WFI immediately, something unknown happend. + * Fall through AND loop back to the checks. Failing which retry WFI. + */ +#endif + /* + * CPU0 and CPU1 are release together from OFF mode, however, + * CPU0 can be busy doing restore operations while waking + * from OFF mode, However, for many PPA services we need + * CPU0, so, we ask CPU1 to loop back to stagger CPU1 behind CPU0 + */ + b omap4_cpu_resume + +ppa_cp15_cpu1_configure: + /* + * Configure CP15 for CPU1 on HS devices: + * In HS devices CPU0's CP15 is configured at wakeup by PPA, CPU1 must + * call PPA to configure it. + * In 4430 devices CPU1 this call also enables the access to SMP bit, + * on 4460 devices, CPU1 will have SMP bit access by default. + */ + mov r0, #PPA_SERVICE_DEFAULT_POR_NS_SMP + adr r3, ppa_zero_params @ Pointer to parameters + LM_CALL_PPA_SERVICE_PA + isb + dsb + cmp r0, #0x0 @ API returns 0 on success. + bne ppa_cp15_cpu1_configure @ retry if we did succeed + + /* Fall through to continue with boot */ + +continue_boot: + +#ifdef CONFIG_CACHE_L2X0 + /* + * Restore the L2 AUXCTRL and enable the L2 cache. + * 0x109 = Program the L2X0 AUXCTRL + * 0x102 = Enable the L2 using L2X0 CTRL + * register r0 contains value to be programmed. + * L2 cache is already invalidate by ROM code as part + * of MPUSS OFF wakeup path. + */ + ldr r2, =OMAP44XX_L2CACHE_BASE + ldr r0, [r2, #L2X0_CTRL] + and r0, #0x0f + cmp r0, #1 + beq skip_l2en @ Skip if already enabled + +check_por: + ldr r0, =OMAP44XX_SAR_RAM_BASE @ Check DEVICE type + ldr r1, [r0, #OMAP_TYPE_OFFSET] + cmp r1, #0x1 @ Check for HS device + bne skip_por + ldr r0, =PPA_SERVICE_PL310_POR @ Setup PPA HAL call + ldr r1, =OMAP44XX_SAR_RAM_BASE + ldr r4, [r1, #L2X0_PREFETCHCTRL_OFFSET] + adr r3, POR_params + str r4, [r3, #0x04] + LM_CALL_PPA_SERVICE_PA +skip_por: + ldr r3, =OMAP44XX_SAR_RAM_BASE + ldr r0, [r3, #L2X0_AUXCTRL_OFFSET] + ldr r12, =0x109 @ Setup L2 AUXCTRL value + dsb + smc #0 + + ldr r2, =OMAP44XX_L2CACHE_BASE + ldr r4, =OMAP44XX_SAR_RAM_BASE + ldr r9, [r4, #L2X0_LOCKDOWN_OFFSET0] + str r9, [r2, #L2X0_LOCKDOWN_WAY_D0] + str r9, [r2, #L2X0_LOCKDOWN_WAY_D1] + str r9, [r2, #L2X0_LOCKDOWN_WAY_I0] + str r9, [r2, #L2X0_LOCKDOWN_WAY_I1] + + dsb + mov r0, #0x1 + ldr r12, =0x102 @ Enable L2 Cache controller + dsb + smc #0 + dsb +skip_l2en: +#endif + + /* Check if we have Public access to SMP bit */ + mrc p15, 0, r0, c1, c1, 2 @ Read NSACR data + tst r0, #(1 << 18) + beq skip_ns_smp_enable @ Skip if still no access + + /* Set the SMP bit if it is not already set */ + mrc p15, 0, r0, c1, c0, 1 + tst r0, #(1 << 6) @ Check SMP bit enabled? + orreq r0, r0, #(1 << 6) + mcreq p15, 0, r0, c1, c0, 1 + isb +skip_ns_smp_enable: + + /* + * Check the wakeup cpuid and use appropriate + * SAR BANK location for context restore. + */ + ldr r3, =OMAP44XX_SAR_RAM_BASE + mov r1, #0 + mcr p15, 0, r1, c7, c5, 0 @ Invalidate L1 I + mrc p15, 0, r0, c0, c0, 5 @ MPIDR + ands r0, r0, #0x0f + orreq r3, r3, #CPU0_SAVE_OFFSET + orrne r3, r3, #CPU1_SAVE_OFFSET + + /* Restore cp15 registers */ + ldmia r3!, {r4-r6} + mov sp, r4 @ Restore sp + msr spsr_cxsf, r5 @ Restore spsr + mov lr, r6 @ Restore lr + + /* c1 and c2 registers */ + ldmia r3!, {r4-r7} + mcr p15, 0, r4, c1, c0, 2 @ CPACR + mcr p15, 0, r5, c2, c0, 0 @ TTBR0 + mcr p15, 0, r6, c2, c0, 1 @ TTBR1 + mcr p15, 0, r7, c2, c0, 2 @ TTBCR + + /* c3 and c10 registers */ + ldmia r3!,{r4-r6} + mcr p15, 0, r4, c3, c0, 0 @ DACR + mcr p15, 0, r5, c10, c2, 0 @ PRRR + mcr p15, 0, r6, c10, c2, 1 @ NMRR + + /* c12, c13 and CPSR registers */ + ldmia r3!,{r4-r7} + mcr p15, 0, r4, c13, c0, 1 @ Context ID + mcr p15, 0, r5, c13, c0, 2 @ User r/w thread ID + mcr p15, 0, r6, c12, c0, 0 @ Secure or NS VBAR + msr cpsr, r7 @ store cpsr + + /* + * Enabling MMU here. Page entry needs to be altered + * to create temporary 1:1 map and then resore the entry + * ones MMU is enabled + */ + mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl + and r7, #0x7 @ Extract N (0:2) to decide + cmp r7, #0x0 @ TTBR0/TTBR1 + beq use_ttbr0 +ttbr_error: + b ttbr_error @ Only N = 0 supported +use_ttbr0: + mrc p15, 0, r2, c2, c0, 0 @ Read TTBR0 + ldr r5, =TTRBIT_MASK + and r2, r5 + mov r4, pc + ldr r5, =TABLE_INDEX_MASK + and r4, r5 @ r4 = 31 to 20 bits of pc + ldr r1, =TABLE_ENTRY + add r1, r1, r4 @ r1 has value of table entry + lsr r4, #18 @ Address of table entry + add r2, r4 @ r2 - location to be modified + + /* Ensure the modified entry makes it to main memory */ +#ifdef CONFIG_CACHE_L2X0 + ldr r5, =OMAP44XX_L2CACHE_BASE + str r2, [r5, #L2X0_CLEAN_INV_LINE_PA] +wait_l2: + ldr r0, [r5, #L2X0_CLEAN_INV_LINE_PA] + ands r0, #1 + bne wait_l2 +#endif + + /* Storing previous entry of location being modified */ + ldr r5, =OMAP44XX_SAR_RAM_BASE + ldr r4, [r2] + mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR + ands r0, r0, #0x0f + streq r4, [r5, #MMU_OFFSET0] @ Modify the table entry + strne r4, [r5, #MMU_OFFSET1] + str r1, [r2] + + /* + * Storing address of entry being modified + * It will be restored after enabling MMU + */ + ldr r5, =OMAP44XX_SAR_RAM_BASE + mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR + ands r0, r0, #0x0f + orreq r5, r5, #MMU_OFFSET0 + orrne r5, r5, #MMU_OFFSET1 + str r2, [r5, #TABLE_ADDRESS_OFFSET] + mov r0, #0 + mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer + mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB + mcr p15, 0, r0, c8, c5, 0 @ Invalidate ITLB + mcr p15, 0, r0, c8, c6, 0 @ Invalidate DTLB + + /* + * Restore control register but don't enable Data caches here. + * Caches will be enabled after restoring MMU table entry. + */ + ldmia r3!, {r4} + str r4, [r5, #CR_VALUE_OFFSET] @ Store previous value of CR + ldr r2, =CACHE_DISABLE_MASK + and r4, r2 + mcr p15, 0, r4, c1, c0, 0 + isb + dsb + ldr r0, =mmu_on_label + bx r0 +mmu_on_label: + /* Set up the per-CPU stacks */ + bl cpu_init + + /* + * Restore the MMU table entry that was modified for + * enabling MMU. + */ + bl omap4_get_sar_ram_base + mov r8, r0 + mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR + ands r0, r0, #0x0f + orreq r8, r8, #MMU_OFFSET0 @ Get address of entry that.. + orrne r8, r8, #MMU_OFFSET1 @ was modified + ldr r2, [r8, #TABLE_ADDRESS_OFFSET] + ldr r3, =local_va2pa_offet + add r2, r2, r3 + ldr r0, [r8] @ Get the previous value.. + str r0, [r2] @ which needs to be restored + mov r0, #0 + mcr p15, 0, r0, c7, c1, 6 @ flush TLB and issue barriers + mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer + mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB + mcr p15, 0, r0, c8, c5, 0 @ Invalidate ITLB + mcr p15, 0, r0, c8, c6, 0 @ Invalidate DTLB + dsb + isb + ldr r0, [r8, #CR_VALUE_OFFSET] @ Restore the Control register + mcr p15, 0, r0, c1, c0, 0 @ with caches enabled. + isb + + ldmfd sp!, {r0-r12, pc} @ restore regs and return + + .equ local_va2pa_offet, (PLAT_PHYS_OFFSET + PAGE_OFFSET) + +ENDPROC(omap4_cpu_resume) + +ENTRY(omap_bus_sync) + stmfd sp!, {r9, lr} + /* SO write to drain of MPU-2-DDR T2ASYNC FIFO */ + bl omap_get_dram_barrier_base + ldr r2, [r0] + str r2, [r0] + /* SO write to drain MPU-2-L3 T2ASYNC FIFO */ + bl omap_get_sram_barrier_base + ldr r2, [r0] + str r2, [r0] + isb + ldmfd sp!, {r9, pc} +ENDPROC(omap_bus_sync) + +ENTRY(omap_do_wfi) + stmfd sp!, {lr} + /* Drain interconnect write buffers. */ + bl omap_bus_sync + + /* + * Execute an ISB instruction to ensure that all of the + * CP15 register changes have been committed. + */ + isb + + /* + * Execute a barrier instruction to ensure that all cache, + * TLB and branch predictor maintenance operations issued + * by any CPU in the cluster have completed. + */ + dsb + dmb + + /* + * Execute a WFI instruction and wait until the + * STANDBYWFI output is asserted to indicate that the + * CPU is in idle and low power state. CPU can specualatively + * prefetch the instructions so add NOPs after WFI. Sixteen + * NOPs as per Cortex-A9 pipeline. + */ + wfi @ Wait For Interrupt + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + ldmfd sp!, {pc} +ENDPROC(omap_do_wfi) + +#endif diff --git a/arch/arm/mach-omap2/smartreflex-class1p5.c b/arch/arm/mach-omap2/smartreflex-class1p5.c new file mode 100644 index 0000000..2090884 --- /dev/null +++ b/arch/arm/mach-omap2/smartreflex-class1p5.c @@ -0,0 +1,678 @@ +/* + * Smart reflex Class 1.5 specific implementations + * + * Copyright (C) 2010-2011 Texas Instruments, Inc. + * Nishanth Menon <nm@ti.com> + * + * Smart reflex class 1.5 is also called periodic SW Calibration + * Some of the highlights are as follows: + * – Host CPU triggers OPP calibration when transitioning to non calibrated + * OPP + * – SR-AVS + VP modules are used to perform calibration + * – Once completed, the SmartReflex-AVS module can be disabled + * – Enables savings based on process, supply DC accuracy and aging + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/kobject.h> +#include <linux/workqueue.h> +#include <linux/slab.h> +#include <linux/opp.h> + +#include "smartreflex.h" +#include "voltage.h" +#include "dvfs.h" + +#define MAX_VDDS 3 +#define SR1P5_SAMPLING_DELAY_MS 1 +#define SR1P5_STABLE_SAMPLES 10 +#define SR1P5_MAX_TRIGGERS 5 + +/* + * We expect events in 10uS, if we don't receive it in twice as long, + * we stop waiting for the event and use the current value + */ +#define MAX_CHECK_VPTRANS_US 20 + +/** + * struct sr_class1p5_work_data - data meant to be used by calibration work + * @work: calibration work + * @voltdm: voltage domain for which we are triggering + * @vdata: voltage data we are calibrating + * @num_calib_triggers: number of triggers from calibration loop + * @num_osc_samples: number of samples collected by isr + * @u_volt_samples: private data for collecting voltage samples in + * case oscillations. filled by the notifier and + * consumed by the work item. + * @work_active: have we scheduled a work item? + */ +struct sr_class1p5_work_data { + struct delayed_work work; + struct voltagedomain *voltdm; + struct omap_volt_data *vdata; + u8 num_calib_triggers; + u8 num_osc_samples; + unsigned long u_volt_samples[SR1P5_STABLE_SAMPLES]; + bool work_active; +}; + +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY +/* recal_work: recalibration calibration work */ +static struct delayed_work recal_work; +#endif + +/** + * sr_class1p5_notify() - isr notifier for status events + * @voltdm: voltage domain for which we were triggered + * @voltdm_cdata: voltage domain specific private class data + * @status: notifier event to use + * + * This basically collects data for the work to use. + */ +static int sr_class1p5_notify(struct voltagedomain *voltdm, + void *voltdm_cdata, + u32 status) +{ + struct sr_class1p5_work_data *work_data; + int idx = 0; + + if (IS_ERR_OR_NULL(voltdm)) { + pr_err("%s: bad parameters!\n", __func__); + return -EINVAL; + } + + work_data = (struct sr_class1p5_work_data *)voltdm_cdata; + if (IS_ERR_OR_NULL(work_data)) { + pr_err("%s:%s no work data!!\n", __func__, voltdm->name); + return -EINVAL; + } + + /* Wait for transdone so that we know the voltage to read */ + do { + if (omap_vp_is_transdone(voltdm)) + break; + idx++; + /* get some constant delay */ + udelay(1); + } while (idx < MAX_CHECK_VPTRANS_US); + + /* + * NOTE: + * If we timeout, we still read the data, + * if we are oscillating+irq latencies are too high, we could + * have scenarios where we miss transdone event. since + * we waited long enough, it is still safe to read the voltage + * as we would have waited long enough - Dont warn for this. + */ + idx = (work_data->num_osc_samples) % SR1P5_STABLE_SAMPLES; + work_data->u_volt_samples[idx] = omap_vp_get_curr_volt(voltdm); + work_data->num_osc_samples++; + + omap_vp_clear_transdone(voltdm); + + + return 0; +} + +/** + * sr_class1p5_calib_work() - work which actually does the calibration + * @work: pointer to the work + * + * calibration routine uses the following logic: + * on the first trigger, we start the isr to collect sr voltages + * wait for stabilization delay (reschdule self instead of sleeping) + * after the delay, see if we collected any isr events + * if none, we have calibrated voltage. + * if there are any, we retry untill we giveup. + * on retry timeout, select a voltage to use as safe voltage. + */ +static void sr_class1p5_calib_work(struct work_struct *work) +{ + struct sr_class1p5_work_data *work_data = + container_of(work, struct sr_class1p5_work_data, work.work); + unsigned long u_volt_safe = 0, u_volt_current = 0, u_volt_margin = 0; + struct omap_volt_data *volt_data; + struct voltagedomain *voltdm; + int idx = 0; + + if (!work) { + pr_err("%s: ooops.. null work_data?\n", __func__); + return; + } + + /* + * Handle the case where we might have just been scheduled AND + * 1.5 disable was called. + */ + if (!mutex_trylock(&omap_dvfs_lock)) { + schedule_delayed_work(&work_data->work, + msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS * + SR1P5_STABLE_SAMPLES)); + return; + } + + voltdm = work_data->voltdm; + /* + * In the unlikely case that we did get through when unplanned, + * flag and return. + */ + if (unlikely(!work_data->work_active)) { + pr_err("%s:%s unplanned work invocation!\n", __func__, + voltdm->name); + mutex_unlock(&omap_dvfs_lock); + return; + } + + volt_data = work_data->vdata; + + work_data->num_calib_triggers++; + /* if we are triggered first time, we need to start isr to sample */ + if (work_data->num_calib_triggers == 1) { + /* We could be interrupted many times, so, only for debug */ + pr_debug("%s: %s: Calibration start: Voltage Nominal=%d\n", + __func__, voltdm->name, volt_data->volt_nominal); + goto start_sampling; + } + + /* Stop isr from interrupting our measurements :) */ + sr_notifier_control(voltdm, false); + + /* + * Quit sampling + * a) if we have oscillations + * b) if we have nominal voltage as the voltage + */ + if (work_data->num_calib_triggers == SR1P5_MAX_TRIGGERS) + goto stop_sampling; + + /* if there are no samples captured.. SR is silent, aka stability! */ + if (!work_data->num_osc_samples) { + /* Did we interrupt too early? */ + u_volt_current = omap_vp_get_curr_volt(voltdm); + if (u_volt_current >= volt_data->volt_nominal) + goto start_sampling; + u_volt_safe = u_volt_current; + goto done_calib; + } + + /* we have potential oscillations/first sample */ +start_sampling: + work_data->num_osc_samples = 0; + + /* Clear transdone events so that we can go on. */ + do { + if (!omap_vp_is_transdone(voltdm)) + break; + idx++; + /* get some constant delay */ + udelay(1); + omap_vp_clear_transdone(voltdm); + } while (idx < MAX_CHECK_VPTRANS_US); + if (idx >= MAX_CHECK_VPTRANS_US) + pr_warning("%s: timed out waiting for transdone clear!!\n", + __func__); + + /* Clear pending events */ + sr_notifier_control(voltdm, false); + /* trigger sampling */ + sr_notifier_control(voltdm, true); + schedule_delayed_work(&work_data->work, + msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS * + SR1P5_STABLE_SAMPLES)); + mutex_unlock(&omap_dvfs_lock); + return; + +stop_sampling: + /* + * We are here for Oscillations due to two scenarios: + * a) SR is attempting to adjust voltage lower than VLIMITO + * which VP will ignore, but SR will re-attempt + * b) actual oscillations + * NOTE: For debugging, enable debug to see the samples. + */ + pr_warning("%s: %s Stop sampling: Voltage Nominal=%d samples=%d\n", + __func__, work_data->voltdm->name, + volt_data->volt_nominal, work_data->num_osc_samples); + + /* pick up current voltage */ + u_volt_current = omap_vp_get_curr_volt(voltdm); + + /* Just in case we got more interrupts than our tiny buffer */ + if (work_data->num_osc_samples > SR1P5_STABLE_SAMPLES) + idx = SR1P5_STABLE_SAMPLES; + else + idx = work_data->num_osc_samples; + /* Index at 0 */ + idx -= 1; + u_volt_safe = u_volt_current; + /* Grab the max of the samples as the stable voltage */ + for (; idx >= 0; idx--) { + pr_debug("%s: osc_v[%d]=%ld, safe_v=%ld\n", __func__, idx, + work_data->u_volt_samples[idx], u_volt_safe); + if (work_data->u_volt_samples[idx] > u_volt_safe) + u_volt_safe = work_data->u_volt_samples[idx]; + } + + /* Fall through to close up common stuff */ +done_calib: + sr_disable_errgen(voltdm); + omap_vp_disable(voltdm); + sr_disable(voltdm); + + /* Add margin if needed */ + if (volt_data->volt_margin) { + struct omap_voltdm_pmic *pmic = voltdm->pmic; + /* Convert to rounded to PMIC step level if available */ + if (pmic && pmic->vsel_to_uv && pmic->uv_to_vsel) { + /* + * To ensure conversion works: + * use a proper base voltage - we use the current volt + * then convert it with pmic routine to vsel and back + * to voltage, and finally remove the base voltage + */ + u_volt_margin = u_volt_current + volt_data->volt_margin; + u_volt_margin = pmic->uv_to_vsel(u_volt_margin); + u_volt_margin = pmic->vsel_to_uv(u_volt_margin); + u_volt_margin -= u_volt_current; + } else { + u_volt_margin = volt_data->volt_margin; + } + + u_volt_safe += u_volt_margin; + } + + if (u_volt_safe > volt_data->volt_nominal) { + pr_warning("%s: %s Vsafe %ld > Vnom %d. %ld[%d] margin on" + "vnom %d curr_v=%ld\n", __func__, voltdm->name, + u_volt_safe, volt_data->volt_nominal, u_volt_margin, + volt_data->volt_margin, volt_data->volt_nominal, + u_volt_current); + } + + volt_data->volt_calibrated = u_volt_safe; + /* Setup my dynamic voltage for the next calibration for this opp */ + volt_data->volt_dynamic_nominal = omap_get_dyn_nominal(volt_data); + + /* + * if the voltage we decided as safe is not the current voltage, + * switch + */ + if (volt_data->volt_calibrated != u_volt_current) { + pr_debug("%s: %s reconfiguring to voltage %d\n", + __func__, voltdm->name, volt_data->volt_calibrated); + voltdm_scale(voltdm, volt_data); + } + + pr_info("%s: %s: Calibration complete: Voltage:Nominal=%d," + "Calib=%d,margin=%d\n", + __func__, voltdm->name, volt_data->volt_nominal, + volt_data->volt_calibrated, volt_data->volt_margin); + /* + * TODO: Setup my wakeup voltage to allow immediate going to OFF and + * on - Pending twl and voltage layer cleanups. + * This is necessary, as this is not done as part of regular + * Dvfs flow. + * vc_setup_on_voltage(voltdm, volt_data->volt_calibrated); + */ + work_data->work_active = false; + mutex_unlock(&omap_dvfs_lock); +} + +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY + +/** + * sr_class1p5_voltdm_recal() - Helper routine to reset calibration. + * @voltdm: Voltage domain to reset calibration for + * @user: unused + * + * NOTE: Appropriate locks must be held by calling path to ensure mutual + * exclusivity + */ +static int sr_class1p5_voltdm_recal(struct voltagedomain *voltdm, + void *user) +{ + struct omap_volt_data *vdata; + + /* + * we need to go no further if sr is not enabled for this domain or + * voltage processor is not present for this voltage domain + * (example vdd_wakeup). Class 1.5 requires Voltage processor + * to function. + */ + if (!voltdm->vp || !is_sr_enabled(voltdm)) + return 0; + + vdata = omap_voltage_get_curr_vdata(voltdm); + if (!vdata) { + pr_err("%s: unable to find current voltage for vdd_%s\n", + __func__, voltdm->name); + return -ENXIO; + } + + omap_sr_disable(voltdm); + omap_voltage_calib_reset(voltdm); + voltdm_reset(voltdm); + omap_sr_enable(voltdm, vdata); + pr_info("%s: %s: calibration reset\n", __func__, voltdm->name); + + return 0; +} + +/** + * sr_class1p5_recal_work() - work which actually does the calibration + * @work: pointer to the work + * + * on a periodic basis, we come and reset our calibration setup + * so that a recalibration of the OPPs take place. This takes + * care of aging factor in the system. + */ +static void sr_class1p5_recal_work(struct work_struct *work) +{ + mutex_lock(&omap_dvfs_lock); + if (voltdm_for_each(sr_class1p5_voltdm_recal, NULL)) + pr_err("%s: Recalibration failed\n", __func__); + mutex_unlock(&omap_dvfs_lock); + /* We come back again after time the usual delay */ + schedule_delayed_work(&recal_work, + msecs_to_jiffies + (CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY)); +} +#endif /* CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY */ + +/** + * sr_class1p5_enable() - class 1.5 mode of enable for a voltage domain + * @voltdm: voltage domain to enable SR for + * @voltdm_cdata: voltage domain specific private class data + * @volt_data: voltdata for the current OPP being transitioned to + * + * when this gets called, we use the h/w loop to setup our voltages + * to an calibrated voltage, detect any oscillations, recover from the same + * and finally store the optimized voltage as the calibrated voltage in the + * system. + * + * NOTE: Appropriate locks must be held by calling path to ensure mutual + * exclusivity + */ +static int sr_class1p5_enable(struct voltagedomain *voltdm, + void *voltdm_cdata, + struct omap_volt_data *volt_data) +{ + int r; + struct sr_class1p5_work_data *work_data; + + if (IS_ERR_OR_NULL(voltdm) || IS_ERR_OR_NULL(volt_data)) { + pr_err("%s: bad parameters!\n", __func__); + return -EINVAL; + } + + /* If already calibrated, nothing to do here.. */ + if (volt_data->volt_calibrated) + return 0; + + work_data = (struct sr_class1p5_work_data *)voltdm_cdata; + if (IS_ERR_OR_NULL(work_data)) { + pr_err("%s: bad work data??\n", __func__); + return -EINVAL; + } + + if (work_data->work_active) + return 0; + + omap_vp_enable(voltdm); + r = sr_enable(voltdm, volt_data); + if (r) { + pr_err("%s: sr[%s] failed\n", __func__, voltdm->name); + sr_disable_errgen(voltdm); + omap_vp_disable(voltdm); + return r; + } + work_data->vdata = volt_data; + work_data->work_active = true; + work_data->num_calib_triggers = 0; + /* program the workqueue and leave it to calibrate offline.. */ + schedule_delayed_work(&work_data->work, + msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS * + SR1P5_STABLE_SAMPLES)); + + return 0; +} + +/** + * sr_class1p5_disable() - disable 1.5 mode for a voltage domain + * @voltdm: voltage domain for the sr which needs disabling + * @volt_data: voltage data for current OPP to disable + * @voltdm_cdata: voltage domain specific private class data + * @is_volt_reset: reset the voltage? + * + * This function has the necessity to either disable SR alone OR disable SR + * and reset voltage to appropriate level depending on is_volt_reset parameter. + * + * Disabling SR H/w loop: + * If calibration is complete or not yet triggered, we have no need to disable + * SR h/w loop. + * If calibration is complete, we would have already disabled SR AVS at the end + * of calibration and h/w loop is inactive when this is called. + * If it was never calibrated before, H/w loop was never enabled in the first + * place to disable. + * If calibration is underway, we cancel the work queue and disable SR. This is + * to provide priority to DVFS transition as such transitions cannot wait + * without impacting user experience. + * + * Resetting voltage: + * If we have already completed calibration, then resetting to nominal voltage + * is not required as we are functioning at safe voltage levels. + * If we have not started calibration, we would like to reset to nominal voltage + * If calibration is underway and we are attempting to reset voltage as + * well, it implies we are in idle/suspend paths where we give priority + * to calibration activity and a retry will be attempted. + * + * NOTE: Appropriate locks must be held by calling path to ensure mutual + * exclusivity + */ +static int sr_class1p5_disable(struct voltagedomain *voltdm, + void *voltdm_cdata, + struct omap_volt_data *volt_data, + int is_volt_reset) +{ + struct sr_class1p5_work_data *work_data; + + if (IS_ERR_OR_NULL(voltdm) || IS_ERR_OR_NULL(volt_data)) { + pr_err("%s: bad parameters!\n", __func__); + return -EINVAL; + } + + work_data = (struct sr_class1p5_work_data *)voltdm_cdata; + if (IS_ERR_OR_NULL(work_data)) { + pr_err("%s: bad work data??\n", __func__); + return -EINVAL; + } + if (work_data->work_active) { + /* if volt reset and work is active, we dont allow this */ + if (is_volt_reset) + return -EBUSY; + /* flag work is dead and remove the old work */ + work_data->work_active = false; + cancel_delayed_work_sync(&work_data->work); + sr_notifier_control(voltdm, false); + sr_disable_errgen(voltdm); + omap_vp_disable(voltdm); + sr_disable(voltdm); + } + + /* If already calibrated, don't need to reset voltage */ + if (volt_data->volt_calibrated) + return 0; + + if (is_volt_reset) + voltdm_reset(voltdm); + return 0; +} + +/** + * sr_class1p5_configure() - configuration function + * @voltdm: configure for which voltage domain + * @voltdm_cdata: voltage domain specific private class data + * + * we dont do much here other than setup some registers for + * the sr module involved. + */ +static int sr_class1p5_configure(struct voltagedomain *voltdm, + void *voltdm_cdata) +{ + if (IS_ERR_OR_NULL(voltdm)) { + pr_err("%s: bad parameters!\n", __func__); + return -EINVAL; + } + + return sr_configure_errgen(voltdm); +} + +/** + * sr_class1p5_init() - class 1p5 init + * @voltdm: sr voltage domain + * @voltdm_cdata: voltage domain specific private class data + * allocated by class init with work item data + * freed by deinit. + * @class_priv_data: private data for the class (unused) + * + * we do class specific initialization like creating sysfs/debugfs entries + * needed, spawning of a kthread if needed etc. + */ +static int sr_class1p5_init(struct voltagedomain *voltdm, + void **voltdm_cdata, void *class_priv_data) +{ + struct sr_class1p5_work_data *work_data; + + if (IS_ERR_OR_NULL(voltdm) || IS_ERR_OR_NULL(voltdm_cdata)) { + pr_err("%s: bad parameters!\n", __func__); + return -EINVAL; + } + + if (!IS_ERR_OR_NULL(*voltdm_cdata)) { + pr_err("%s: ooopps.. class already initialized for %s! bug??\n", + __func__, voltdm->name); + return -EINVAL; + } + /* setup our work params */ + work_data = kzalloc(sizeof(struct sr_class1p5_work_data), GFP_KERNEL); + if (!work_data) { + pr_err("%s: no memory to allocate work data on domain %s\n", + __func__, voltdm->name); + return -ENOMEM; + } + + work_data->voltdm = voltdm; + INIT_DELAYED_WORK_DEFERRABLE(&work_data->work, sr_class1p5_calib_work); + *voltdm_cdata = (void *)work_data; + + return 0; +} + +/** + * sr_class1p5_deinit() - class 1p5 deinitialization + * @voltdm: voltage domain for which to do this. + * @voltdm_cdata: voltage domain specific private class data + * allocated by class init with work item data + * freed by deinit. + * @class_priv_data: class private data for deinitialiation (unused) + * + * currently only resets the calibrated voltage forcing DVFS voltages + * to be used in the system + * + * NOTE: Appropriate locks must be held by calling path to ensure mutual + * exclusivity + */ +static int sr_class1p5_deinit(struct voltagedomain *voltdm, + void **voltdm_cdata, void *class_priv_data) +{ + struct sr_class1p5_work_data *work_data; + + if (IS_ERR_OR_NULL(voltdm) || IS_ERR_OR_NULL(voltdm_cdata)) { + pr_err("%s: bad parameters!\n", __func__); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(*voltdm_cdata)) { + pr_err("%s: ooopps.. class not initialized for %s! bug??\n", + __func__, voltdm->name); + return -EINVAL; + } + + work_data = (struct sr_class1p5_work_data *) *voltdm_cdata; + + /* + * we dont have SR periodic calib anymore.. so reset calibs + * we are already protected by appropriate locks, so no lock needed + * here. + */ + if (work_data->work_active) + sr_class1p5_disable(voltdm, work_data, work_data->vdata, 0); + + /* Ensure worker canceled. */ + cancel_delayed_work_sync(&work_data->work); + omap_voltage_calib_reset(voltdm); + voltdm_reset(voltdm); + + *voltdm_cdata = NULL; + kfree(work_data); + + return 0; +} + +/* SR class1p5 structure */ +static struct omap_sr_class_data class1p5_data = { + .enable = sr_class1p5_enable, + .disable = sr_class1p5_disable, + .configure = sr_class1p5_configure, + .class_type = SR_CLASS1P5, + .init = sr_class1p5_init, + .deinit = sr_class1p5_deinit, + .notify = sr_class1p5_notify, + /* + * trigger for bound - this tells VP that SR has a voltage + * change. we should try and ensure transdone is set before reading + * vp voltage. + */ + .notify_flags = SR_NOTIFY_MCUBOUND, +}; + +/** + * sr_class1p5_driver_init() - register class 1p5 as default + * + * board files call this function to use class 1p5, we register with the + * smartreflex subsystem + */ +static int __init sr_class1p5_driver_init(void) +{ + int r; + + /* Enable this class only for OMAP3630 and OMAP4 */ + if (!(cpu_is_omap3630() || cpu_is_omap44xx())) + return -EINVAL; + + r = sr_register_class(&class1p5_data); + if (r) { + pr_err("SmartReflex class 1.5 driver: " + "failed to register with %d\n", r); + } else { +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY + INIT_DELAYED_WORK_DEFERRABLE(&recal_work, + sr_class1p5_recal_work); + schedule_delayed_work(&recal_work, + msecs_to_jiffies + (CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY)); +#endif + pr_info("SmartReflex class 1.5 driver: initialized (%dms)\n", + CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY); + } + return r; +} +late_initcall(sr_class1p5_driver_init); diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c index f438cf4..9ac1c99 100644 --- a/arch/arm/mach-omap2/smartreflex-class3.c +++ b/arch/arm/mach-omap2/smartreflex-class3.c @@ -11,33 +11,33 @@ * published by the Free Software Foundation. */ +#include <plat/cpu.h> #include "smartreflex.h" -static int sr_class3_enable(struct voltagedomain *voltdm) +static int sr_class3_enable(struct voltagedomain *voltdm, + void *voltdm_cdata, + struct omap_volt_data *volt_data) { - unsigned long volt = omap_voltage_get_nom_volt(voltdm); - - if (!volt) { - pr_warning("%s: Curr voltage unknown. Cannot enable sr_%s\n", - __func__, voltdm->name); - return -ENODATA; - } - omap_vp_enable(voltdm); - return sr_enable(voltdm, volt); + return sr_enable(voltdm, volt_data); } -static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset) +static int sr_class3_disable(struct voltagedomain *voltdm, + void *voltdm_cdata, + struct omap_volt_data *vdata, + int is_volt_reset) { + sr_disable_errgen(voltdm); omap_vp_disable(voltdm); sr_disable(voltdm); if (is_volt_reset) - omap_voltage_reset(voltdm); + voltdm_reset(voltdm); return 0; } -static int sr_class3_configure(struct voltagedomain *voltdm) +static int sr_class3_configure(struct voltagedomain *voltdm, + void *voltdm_cdata) { return sr_configure_errgen(voltdm); } @@ -53,6 +53,10 @@ static struct omap_sr_class_data class3_data = { /* Smartreflex Class3 init API to be called from board file */ static int __init sr_class3_init(void) { + /* Enable this class only for OMAP343x */ + if (!cpu_is_omap343x()) + return -EINVAL; + pr_info("SmartReflex Class3 initialized\n"); return sr_register_class(&class3_data); } diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index f5a6bc1..c2d85c1 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -28,6 +28,7 @@ #include <plat/common.h> #include "pm.h" +#include "dvfs.h" #include "smartreflex.h" #define SMARTREFLEX_NAME_LEN 16 @@ -49,11 +50,14 @@ struct omap_sr { u32 senp_mod; u32 senn_mod; unsigned int irq; + bool irq_enabled; void __iomem *base; struct platform_device *pdev; struct list_head node; struct omap_sr_nvalue_table *nvalue_table; struct voltagedomain *voltdm; + /* Managed by class driver as needed */ + void *voltdm_cdata; struct dentry *dbg_dir; }; @@ -62,6 +66,7 @@ static LIST_HEAD(sr_list); static struct omap_sr_class_data *sr_class; static struct omap_sr_pmic_data *sr_pmic_data; +static struct dentry *sr_dbg_dir; static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value) { @@ -72,10 +77,6 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, u32 value) { u32 reg_val; - u32 errconfig_offs = 0, errconfig_mask = 0; - - reg_val = __raw_readl(sr->base + offset); - reg_val &= ~mask; /* * Smartreflex error config register is special as it contains @@ -86,16 +87,15 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, * if they are currently set, but does allow the caller to write * those bits. */ - if (sr->ip_type == SR_TYPE_V1) { - errconfig_offs = ERRCONFIG_V1; - errconfig_mask = ERRCONFIG_STATUS_V1_MASK; - } else if (sr->ip_type == SR_TYPE_V2) { - errconfig_offs = ERRCONFIG_V2; - errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2; - } + if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1) + mask |= ERRCONFIG_STATUS_V1_MASK; + else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2) + mask |= ERRCONFIG_VPBOUNDINTST_V2; + + reg_val = __raw_readl(sr->base + offset); + reg_val &= ~mask; - if (offset == errconfig_offs) - reg_val &= ~errconfig_mask; + value &= mask; reg_val |= value; @@ -124,27 +124,119 @@ static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm) return ERR_PTR(-ENODATA); } +static inline u32 notifier_to_irqen_v1(u8 notify_flags) +{ + u32 val; + + val = (notify_flags & SR_NOTIFY_MCUACCUM) ? + ERRCONFIG_MCUACCUMINTEN : 0; + val |= (notify_flags & SR_NOTIFY_MCUVALID) ? + ERRCONFIG_MCUVALIDINTEN : 0; + val |= (notify_flags & SR_NOTIFY_MCUBOUND) ? + ERRCONFIG_MCUBOUNDINTEN : 0; + val |= (notify_flags & SR_NOTIFY_MCUDISACK) ? + ERRCONFIG_MCUDISACKINTEN : 0; + + return val; +} + +static inline u32 notifier_to_irqen_v2(u8 notify_flags) +{ + u32 val; + + val = (notify_flags & SR_NOTIFY_MCUACCUM) ? + IRQENABLE_MCUACCUMINT : 0; + val |= (notify_flags & SR_NOTIFY_MCUVALID) ? + IRQENABLE_MCUVALIDINT : 0; + val |= (notify_flags & SR_NOTIFY_MCUBOUND) ? + IRQENABLE_MCUBOUNDSINT : 0; + val |= (notify_flags & SR_NOTIFY_MCUDISACK) ? + IRQENABLE_MCUDISABLEACKINT : 0; + + return val; +} + +static inline u8 irqstat_to_notifier_v1(u32 status) +{ + u8 val; + + val = (status & ERRCONFIG_MCUACCUMINTST) ? + SR_NOTIFY_MCUACCUM : 0; + val |= (status & ERRCONFIG_MCUVALIDINTEN) ? + SR_NOTIFY_MCUVALID : 0; + val |= (status & ERRCONFIG_MCUBOUNDINTEN) ? + SR_NOTIFY_MCUBOUND : 0; + val |= (status & ERRCONFIG_MCUDISACKINTEN) ? + SR_NOTIFY_MCUDISACK : 0; + + return val; +} + +static inline u8 irqstat_to_notifier_v2(u32 status) +{ + u8 val; + + val = (status & IRQENABLE_MCUACCUMINT) ? + SR_NOTIFY_MCUACCUM : 0; + val |= (status & IRQENABLE_MCUVALIDINT) ? + SR_NOTIFY_MCUVALID : 0; + val |= (status & IRQENABLE_MCUBOUNDSINT) ? + SR_NOTIFY_MCUBOUND : 0; + val |= (status & IRQENABLE_MCUDISABLEACKINT) ? + SR_NOTIFY_MCUDISACK : 0; + + return val; +} + + static irqreturn_t sr_interrupt(int irq, void *data) { struct omap_sr *sr_info = (struct omap_sr *)data; u32 status = 0; + u32 value = 0; if (sr_info->ip_type == SR_TYPE_V1) { + /* Status bits are one bit before enable bits in v1 */ + value = notifier_to_irqen_v1(sr_class->notify_flags) >> 1; + /* Read the status bits */ status = sr_read_reg(sr_info, ERRCONFIG_V1); + status &= value; /* Clear them by writing back */ - sr_write_reg(sr_info, ERRCONFIG_V1, status); + sr_modify_reg(sr_info, ERRCONFIG_V1, value, status); + + value = irqstat_to_notifier_v1(status); } else if (sr_info->ip_type == SR_TYPE_V2) { + value = notifier_to_irqen_v2(sr_class->notify_flags); /* Read the status bits */ status = sr_read_reg(sr_info, IRQSTATUS); + status &= value; /* Clear them by writing back */ sr_write_reg(sr_info, IRQSTATUS, status); + value = irqstat_to_notifier_v2(status); } - if (sr_class->class_type == SR_CLASS2 && sr_class->notify) - sr_class->notify(sr_info->voltdm, status); + /* Attempt some resemblance of recovery! */ + if (!value) { + dev_err(&sr_info->pdev->dev, "%s: Spurious interrupt!" + "status = 0x%08x. Disabling to prevent spamming!!\n", + __func__, status); + disable_irq_nosync(sr_info->irq); + sr_info->irq_enabled = false; + } else { + /* If the caller reports inability to handle, disable as well */ + if (sr_class->notify && sr_class->notify(sr_info->voltdm, + sr_info->voltdm_cdata, value)) { + dev_err(&sr_info->pdev->dev, "%s: Callback cant handle!" + "status=0x%08x. Disabling to prevent spam!!\n", + __func__, status); + disable_irq_nosync(sr_info->irq); + sr_info->irq_enabled = false; + } + + } return IRQ_HANDLED; } @@ -214,6 +306,7 @@ static void sr_set_regfields(struct omap_sr *sr) static void sr_start_vddautocomp(struct omap_sr *sr) { + int r; if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) { dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not registered\n", @@ -221,8 +314,23 @@ static void sr_start_vddautocomp(struct omap_sr *sr) return; } - if (!sr_class->enable(sr->voltdm)) + /* pause dvfs from interfereing with our operations */ + mutex_lock(&omap_dvfs_lock); + + if (sr_class->init && + sr_class->init(sr->voltdm, &sr->voltdm_cdata, + sr_class->class_priv_data)) { + dev_err(&sr->pdev->dev, + "%s: SRClass initialization failed\n", __func__); + mutex_unlock(&omap_dvfs_lock); + return; + } + + r = sr_class->enable(sr->voltdm, sr->voltdm_cdata, + omap_voltage_get_curr_vdata(sr->voltdm)); + if (!r) sr->autocomp_active = true; + mutex_unlock(&omap_dvfs_lock); } static void sr_stop_vddautocomp(struct omap_sr *sr) @@ -235,8 +343,19 @@ static void sr_stop_vddautocomp(struct omap_sr *sr) } if (sr->autocomp_active) { - sr_class->disable(sr->voltdm, 1); + /* Pause dvfs from interfereing with our operations */ + mutex_lock(&omap_dvfs_lock); + sr_class->disable(sr->voltdm, sr->voltdm_cdata, + omap_voltage_get_curr_vdata(sr->voltdm), 1); + if (sr_class->deinit && + sr_class->deinit(sr->voltdm, &sr->voltdm_cdata, + sr_class->class_priv_data)) { + dev_err(&sr->pdev->dev, + "%s: SR[%d]Class deinitialization failed\n", + __func__, sr->srid); + } sr->autocomp_active = false; + mutex_unlock(&omap_dvfs_lock); } } @@ -258,9 +377,7 @@ static int sr_late_init(struct omap_sr *sr_info) struct resource *mem; int ret = 0; - if (sr_class->class_type == SR_CLASS2 && - sr_class->notify_flags && sr_info->irq) { - + if (sr_class->notify && sr_class->notify_flags && sr_info->irq) { name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name); if (name == NULL) { ret = -ENOMEM; @@ -270,6 +387,7 @@ static int sr_late_init(struct omap_sr *sr_info) 0, name, (void *)sr_info); if (ret) goto error; + disable_irq(sr_info->irq); } if (pdata && pdata->enable_on_init) @@ -278,21 +396,23 @@ static int sr_late_init(struct omap_sr *sr_info) return ret; error: - iounmap(sr_info->base); - mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); - list_del(&sr_info->node); - dev_err(&sr_info->pdev->dev, "%s: ERROR in registering" - "interrupt handler. Smartreflex will" - "not function as desired\n", __func__); - kfree(name); - kfree(sr_info); - return ret; + iounmap(sr_info->base); + mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + list_del(&sr_info->node); + dev_err(&sr_info->pdev->dev, "%s: ERROR in registering" + "interrupt handler. Smartreflex will" + "not function as desired\n", __func__); + kfree(name); + kfree(sr_info); + return ret; } static void sr_v1_disable(struct omap_sr *sr) { int timeout = 0; + int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | + ERRCONFIG_MCUBOUNDINTST; /* Enable MCUDisableAcknowledge interrupt */ sr_modify_reg(sr, ERRCONFIG_V1, @@ -301,13 +421,13 @@ static void sr_v1_disable(struct omap_sr *sr) /* SRCONFIG - disable SR */ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); - /* Disable all other SR interrupts and clear the status */ + /* Disable all other SR interrupts and clear the status as needed */ + if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1) + errconf_val |= ERRCONFIG_VPBOUNDINTST_V1; sr_modify_reg(sr, ERRCONFIG_V1, (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1), - (ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | - ERRCONFIG_MCUBOUNDINTST | - ERRCONFIG_VPBOUNDINTST_V1)); + errconf_val); /* * Wait for SR to be disabled. @@ -336,15 +456,23 @@ static void sr_v2_disable(struct omap_sr *sr) /* SRCONFIG - disable SR */ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); - /* Disable all other SR interrupts and clear the status */ - sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, + /* + * Disable all other SR interrupts and clear the status + * write to status register ONLY on need basis - only if status + * is set. + */ + if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2) + sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, ERRCONFIG_VPBOUNDINTST_V2); - sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT | - IRQENABLE_MCUVALIDINT | - IRQENABLE_MCUBOUNDSINT)); + else + sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, + 0x0); sr_write_reg(sr, IRQSTATUS, (IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT | IRQSTATUS_MCBOUNDSINT)); + sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT | + IRQENABLE_MCUVALIDINT | + IRQENABLE_MCUBOUNDSINT)); /* * Wait for SR to be disabled. @@ -359,8 +487,8 @@ static void sr_v2_disable(struct omap_sr *sr) __func__); /* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */ - sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT); sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT); + sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT); } static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs) @@ -384,6 +512,28 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs) /* Public Functions */ /** + * is_sr_enabled() - is Smart reflex enabled for this domain? + * @voltdm: voltage domain to check + * + * Returns 0 if SR is enabled for this domain, else returns err + */ +bool is_sr_enabled(struct voltagedomain *voltdm) +{ + struct omap_sr *sr; + if (IS_ERR_OR_NULL(voltdm)) { + pr_warning("%s: invalid param voltdm\n", __func__); + return false; + } + sr = _sr_lookup(voltdm); + if (IS_ERR(sr)) { + pr_warning("%s: omap_sr struct for sr_%s not found\n", + __func__, voltdm->name); + return false; + } + return sr->autocomp_active; +} + +/** * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the * error generator module. * @voltdm: VDD pointer to which the SR module to be configured belongs to. @@ -446,8 +596,52 @@ int sr_configure_errgen(struct voltagedomain *voltdm) sr_errconfig); /* Enabling the interrupts if the ERROR module is used */ - sr_modify_reg(sr, errconfig_offs, - vpboundint_en, (vpboundint_en | vpboundint_st)); + sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st), + vpboundint_en); + + return 0; +} + +/** + * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component + * @voltdm: voltagedomain pointer to which the SR module to be configured belongs to. + * + * This API is to be called from the smartreflex class driver to + * disable the error generator module inside the smartreflex module. + * + * Returns 0 on success and error value in case of failure. + */ +int sr_disable_errgen(struct voltagedomain *voltdm) +{ + u32 errconfig_offs, vpboundint_en; + u32 vpboundint_st; + struct omap_sr *sr = _sr_lookup(voltdm); + + if (IS_ERR(sr)) { + pr_warning("%s: omap_sr struct for sr_%s not found\n", + __func__, voltdm->name); + return -EINVAL; + } + + if (sr->ip_type == SR_TYPE_V1) { + errconfig_offs = ERRCONFIG_V1; + vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1; + vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1; + } else if (sr->ip_type == SR_TYPE_V2) { + errconfig_offs = ERRCONFIG_V2; + vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2; + vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2; + } else { + dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" + "module without specifying the ip\n", __func__); + return -EINVAL; + } + + /* Disable the interrupts of ERROR module */ + sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0); + + /* Disable the Sensor and errorgen */ + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0); return 0; } @@ -532,7 +726,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm) /** * sr_enable() - Enables the smartreflex module. * @voltdm: VDD pointer to which the SR module to be configured belongs to. - * @volt: The voltage at which the Voltage domain associated with + * @volt_data: The voltage at which the Voltage domain associated with * the smartreflex module is operating at. * This is required only to program the correct Ntarget value. * @@ -540,10 +734,9 @@ int sr_configure_minmax(struct voltagedomain *voltdm) * enable a smartreflex module. Returns 0 on success. Returns error * value if the voltage passed is wrong or if ntarget value is wrong. */ -int sr_enable(struct voltagedomain *voltdm, unsigned long volt) +int sr_enable(struct voltagedomain *voltdm, struct omap_volt_data *volt_data) { u32 nvalue_reciprocal; - struct omap_volt_data *volt_data; struct omap_sr *sr = _sr_lookup(voltdm); int ret; @@ -553,19 +746,16 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt) return -EINVAL; } - volt_data = omap_voltage_get_voltdata(sr->voltdm, volt); - - if (IS_ERR(volt_data)) { - dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table" - "for nominal voltage %ld\n", __func__, volt); - return -ENODATA; + if (IS_ERR_OR_NULL(volt_data)) { + dev_warn(&sr->pdev->dev, "%s: bad voltage data\n", __func__); + return -EINVAL; } nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs); if (!nvalue_reciprocal) { dev_warn(&sr->pdev->dev, "%s: NVALUE = 0 at voltage %ld\n", - __func__, volt); + __func__, omap_get_operation_voltage(volt_data)); return -ENODATA; } @@ -579,7 +769,7 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt) return 0; /* Configure SR */ - ret = sr_class->configure(voltdm); + ret = sr_class->configure(voltdm, sr->voltdm_cdata); if (ret) return ret; @@ -622,7 +812,79 @@ void sr_disable(struct voltagedomain *voltdm) sr_v2_disable(sr); } - pm_runtime_put_sync(&sr->pdev->dev); + pm_runtime_put_sync_suspend(&sr->pdev->dev); +} + +/** + * sr_notifier_control() - control the notifier mechanism + * @voltdm: VDD pointer to which the SR module to be configured belongs to. + * @enable: true to enable notifiers and false to disable the same + * + * SR modules allow an MCU interrupt mechanism that vary based on the IP + * revision, we allow the system to generate interrupt if the class driver + * has capability to handle the same. it is upto the class driver to ensure + * the proper sequencing and handling for a clean implementation. returns + * 0 if all goes fine, else returns failure results + */ +int sr_notifier_control(struct voltagedomain *voltdm, bool enable) +{ + struct omap_sr *sr = _sr_lookup(voltdm); + u32 value = 0; + + if (!sr) { + pr_warning("%s: sr corresponding to domain not found\n", + __func__); + return -EINVAL; + } + if (!sr->autocomp_active) + return -EINVAL; + + /* If I could never register an ISR, why bother?? */ + if (!(sr_class && sr_class->notify && sr_class->notify_flags && + sr->irq)) { + dev_warn(&sr->pdev->dev, + "%s: unable to setup IRQ without handling mechanism\n", + __func__); + return -EINVAL; + } + + + switch (sr->ip_type) { + case SR_TYPE_V1: + value = notifier_to_irqen_v1(sr_class->notify_flags); + break; + case SR_TYPE_V2: + value = notifier_to_irqen_v2(sr_class->notify_flags); + break; + default: + dev_warn(&sr->pdev->dev, "%s: unknown type of sr??\n", + __func__); + return -EINVAL; + } + + if (!enable) + sr_write_reg(sr, IRQSTATUS, value); + + switch (sr->ip_type) { + case SR_TYPE_V1: + sr_modify_reg(sr, ERRCONFIG_V1, value, + (enable) ? value : 0); + break; + case SR_TYPE_V2: + sr_write_reg(sr, (enable) ? IRQENABLE_SET : IRQENABLE_CLR, + value); + break; + } + + if (enable != sr->irq_enabled) { + if (enable) + enable_irq(sr->irq); + else + disable_irq(sr->irq); + sr->irq_enabled = enable; + } + + return 0; } /** @@ -665,13 +927,15 @@ int sr_register_class(struct omap_sr_class_data *class_data) * omap_sr_enable() - API to enable SR clocks and to call into the * registered smartreflex class enable API. * @voltdm: VDD pointer to which the SR module to be configured belongs to. + * @volt_data: Voltage data to go to * * This API is to be called from the kernel in order to enable * a particular smartreflex module. This API will do the initial * configurations to turn on the smartreflex module and in turn call * into the registered smartreflex class enable API. */ -void omap_sr_enable(struct voltagedomain *voltdm) +void omap_sr_enable(struct voltagedomain *voltdm, + struct omap_volt_data *volt_data) { struct omap_sr *sr = _sr_lookup(voltdm); @@ -690,7 +954,8 @@ void omap_sr_enable(struct voltagedomain *voltdm) return; } - sr_class->enable(voltdm); + sr_class->enable(voltdm, sr->voltdm_cdata, + omap_voltage_get_curr_vdata(voltdm)); } /** @@ -723,7 +988,8 @@ void omap_sr_disable(struct voltagedomain *voltdm) return; } - sr_class->disable(voltdm, 0); + sr_class->disable(voltdm, sr->voltdm_cdata, + omap_voltage_get_curr_vdata(voltdm), 0); } /** @@ -736,27 +1002,30 @@ void omap_sr_disable(struct voltagedomain *voltdm) * into the registered smartreflex class disable API. This API will tell * the smartreflex class disable to reset the VP voltage after * disabling smartreflex. + * + * Returns result of transition request. */ -void omap_sr_disable_reset_volt(struct voltagedomain *voltdm) +int omap_sr_disable_reset_volt(struct voltagedomain *voltdm) { struct omap_sr *sr = _sr_lookup(voltdm); if (IS_ERR(sr)) { pr_warning("%s: omap_sr struct for sr_%s not found\n", __func__, voltdm->name); - return; + return -ENODEV; } if (!sr->autocomp_active) - return; + return 0; if (!sr_class || !(sr_class->disable)) { dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not" "registered\n", __func__); - return; + return -ENODEV; } - sr_class->disable(voltdm, 1); + return sr_class->disable(voltdm, sr->voltdm_cdata, + omap_voltage_get_curr_vdata(voltdm), 1); } /** @@ -808,10 +1077,13 @@ static int omap_sr_autocomp_store(void *data, u64 val) return -EINVAL; } - if (!val) - sr_stop_vddautocomp(sr_info); - else - sr_start_vddautocomp(sr_info); + /* control enable/disable only if there is a delta in value */ + if (sr_info->autocomp_active != val) { + if (!val) + sr_stop_vddautocomp(sr_info); + else + sr_start_vddautocomp(sr_info); + } return 0; } @@ -824,9 +1096,10 @@ static int __init omap_sr_probe(struct platform_device *pdev) struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL); struct omap_sr_data *pdata = pdev->dev.platform_data; struct resource *mem, *irq; - struct dentry *vdd_dbg_dir, *nvalue_dir; + struct dentry *nvalue_dir; struct omap_volt_data *volt_data; int i, ret = 0; + char *name; if (!sr_info) { dev_err(&pdev->dev, "%s: unable to allocate sr_info\n", @@ -858,6 +1131,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); pm_runtime_enable(&pdev->dev); + pm_runtime_irq_safe(&pdev->dev); sr_info->pdev = pdev; sr_info->srid = pdev->id; @@ -891,23 +1165,30 @@ static int __init omap_sr_probe(struct platform_device *pdev) ret = sr_late_init(sr_info); if (ret) { pr_warning("%s: Error in SR late init\n", __func__); - return ret; + goto err_iounmap; } } dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__); + if (!sr_dbg_dir) { + sr_dbg_dir = debugfs_create_dir("smartreflex", NULL); + if (!sr_dbg_dir) { + ret = PTR_ERR(sr_dbg_dir); + pr_err("%s:sr debugfs dir creation failed(%d)\n", + __func__, ret); + goto err_iounmap; + } + } - /* - * If the voltage domain debugfs directory is not created, do - * not try to create rest of the debugfs entries. - */ - vdd_dbg_dir = omap_voltage_get_dbgdir(sr_info->voltdm); - if (!vdd_dbg_dir) { - ret = -EINVAL; + name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name); + if (!name) { + dev_err(&pdev->dev, "%s: Unable to alloc debugfs name\n", + __func__); + ret = -ENOMEM; goto err_iounmap; } - - sr_info->dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir); + sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir); + kfree(name); if (IS_ERR(sr_info->dbg_dir)) { dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n", __func__); @@ -998,8 +1279,32 @@ static int __devexit omap_sr_remove(struct platform_device *pdev) return 0; } +static void __devexit omap_sr_shutdown(struct platform_device *pdev) +{ + struct omap_sr_data *pdata = pdev->dev.platform_data; + struct omap_sr *sr_info; + + if (!pdata) { + dev_err(&pdev->dev, "%s: platform data missing\n", __func__); + return; + } + + sr_info = _sr_lookup(pdata->voltdm); + if (IS_ERR(sr_info)) { + dev_warn(&pdev->dev, "%s: omap_sr struct not found\n", + __func__); + return; + } + + if (sr_info->autocomp_active) + sr_stop_vddautocomp(sr_info); + + return; +} + static struct platform_driver smartreflex_driver = { .remove = omap_sr_remove, + .shutdown = omap_sr_shutdown, .driver = { .name = "smartreflex", }, diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h index 5f35b9e..f17c2ec 100644 --- a/arch/arm/mach-omap2/smartreflex.h +++ b/arch/arm/mach-omap2/smartreflex.h @@ -142,6 +142,12 @@ #define OMAP3430_SR_ERRWEIGHT 0x04 #define OMAP3430_SR_ERRMAXLIMIT 0x02 +/* Smart reflex notifiers for class drivers to use */ +#define SR_NOTIFY_MCUDISACK BIT(3) +#define SR_NOTIFY_MCUBOUND BIT(2) +#define SR_NOTIFY_MCUVALID BIT(1) +#define SR_NOTIFY_MCUACCUM BIT(0) + /** * struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass * pmic specific info to smartreflex driver @@ -152,6 +158,15 @@ struct omap_sr_pmic_data { void (*sr_pmic_init) (void); }; +/** + * struct omap_smartreflex_dev_attr - Smartreflex Device attribute. + * + * @sensor_voltdm_name: Name of voltdomain of SR instance + */ +struct omap_smartreflex_dev_attr { + const char *sensor_voltdm_name; +}; + #ifdef CONFIG_OMAP_SMARTREFLEX /* * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR. @@ -162,12 +177,15 @@ struct omap_sr_pmic_data { #define SR_CLASS1 0x1 #define SR_CLASS2 0x2 #define SR_CLASS3 0x3 +#define SR_CLASS1P5 0x4 /** * struct omap_sr_class_data - Smartreflex class driver info * * @enable: API to enable a particular class smaartreflex. * @disable: API to disable a particular class smartreflex. + * @init: API to do class specific initialization (optional) + * @deinit: API to do class specific deinitialization (optional) * @configure: API to configure a particular class smartreflex. * @notify: API to notify the class driver about an event in SR. * Not needed for class3. @@ -175,14 +193,23 @@ struct omap_sr_pmic_data { * @class_type: specify which smartreflex class. * Can be used by the SR driver to take any class * based decisions. + * @class_priv_data: Class specific private data (optional) */ struct omap_sr_class_data { - int (*enable)(struct voltagedomain *voltdm); - int (*disable)(struct voltagedomain *voltdm, int is_volt_reset); - int (*configure)(struct voltagedomain *voltdm); - int (*notify)(struct voltagedomain *voltdm, u32 status); + int (*enable)(struct voltagedomain *voltdm, void *voltdm_cdata, + struct omap_volt_data *volt_data); + int (*disable)(struct voltagedomain *voltdm, void *voltdm_cdata, + struct omap_volt_data *volt_data, int is_volt_reset); + int (*init)(struct voltagedomain *voltdm, void **voltdm_cdata, + void *class_priv_data); + int (*deinit)(struct voltagedomain *voltdm, void **voltdm_cdata, + void *class_priv_data); + int (*configure)(struct voltagedomain *voltdm, void *voltdm_cdata); + int (*notify)(struct voltagedomain *voltdm, void *voltdm_cdata, + u32 status); u8 notify_flags; u8 class_type; + void *class_priv_data; }; /** @@ -220,27 +247,43 @@ struct omap_sr_data { }; /* Smartreflex module enable/disable interface */ -void omap_sr_enable(struct voltagedomain *voltdm); +void omap_sr_enable(struct voltagedomain *voltdm, + struct omap_volt_data *volt_data); void omap_sr_disable(struct voltagedomain *voltdm); -void omap_sr_disable_reset_volt(struct voltagedomain *voltdm); +int omap_sr_disable_reset_volt(struct voltagedomain *voltdm); /* API to register the pmic specific data with the smartreflex driver. */ void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data); /* Smartreflex driver hooks to be called from Smartreflex class driver */ -int sr_enable(struct voltagedomain *voltdm, unsigned long volt); +int sr_enable(struct voltagedomain *voltdm, struct omap_volt_data *volt_data); void sr_disable(struct voltagedomain *voltdm); +int sr_notifier_control(struct voltagedomain *voltdm, bool enable); int sr_configure_errgen(struct voltagedomain *voltdm); +int sr_disable_errgen(struct voltagedomain *voltdm); int sr_configure_minmax(struct voltagedomain *voltdm); /* API to register the smartreflex class driver with the smartreflex driver */ int sr_register_class(struct omap_sr_class_data *class_data); +bool is_sr_enabled(struct voltagedomain *voltdm); #else static inline void omap_sr_enable(struct voltagedomain *voltdm) {} static inline void omap_sr_disable(struct voltagedomain *voltdm) {} -static inline void omap_sr_disable_reset_volt( - struct voltagedomain *voltdm) {} + +static inline int sr_notifier_control(struct voltagedomain *voltdm, + bool enable) +{ + return -EINVAL; +} + +static inline int omap_sr_disable_reset_volt( + struct voltagedomain *voltdm) { return 0; } static inline void omap_sr_register_pmic( struct omap_sr_pmic_data *pmic_data) {} +static inline bool is_sr_enabled(struct voltagedomain *voltdm) +{ + return false; +} #endif + #endif diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c index 10d3c5e..0b74f5b 100644 --- a/arch/arm/mach-omap2/sr_device.c +++ b/arch/arm/mach-omap2/sr_device.c @@ -82,6 +82,7 @@ static int sr_dev_init(struct omap_hwmod *oh, void *user) struct omap_sr_data *sr_data; struct omap_device *od; struct omap_volt_data *volt_data; + struct omap_smartreflex_dev_attr *sr_dev_attr; char *name = "smartreflex"; static int i; @@ -92,9 +93,11 @@ static int sr_dev_init(struct omap_hwmod *oh, void *user) return -ENOMEM; } - if (!oh->vdd_name) { + sr_dev_attr = (struct omap_smartreflex_dev_attr *)oh->dev_attr; + if (!sr_dev_attr || !sr_dev_attr->sensor_voltdm_name) { pr_err("%s: No voltage domain specified for %s." - "Cannot initialize\n", __func__, oh->name); + "Cannot initialize\n", __func__, + oh->name); goto exit; } @@ -102,10 +105,10 @@ static int sr_dev_init(struct omap_hwmod *oh, void *user) sr_data->senn_mod = 0x1; sr_data->senp_mod = 0x1; - sr_data->voltdm = omap_voltage_domain_lookup(oh->vdd_name); + sr_data->voltdm = voltdm_lookup(sr_dev_attr->sensor_voltdm_name); if (IS_ERR(sr_data->voltdm)) { pr_err("%s: Unable to get voltage domain pointer for VDD %s\n", - __func__, oh->vdd_name); + __func__, sr_dev_attr->sensor_voltdm_name); goto exit; } diff --git a/arch/arm/mach-omap2/temp_sensor_device.c b/arch/arm/mach-omap2/temp_sensor_device.c new file mode 100644 index 0000000..0a647a3 --- /dev/null +++ b/arch/arm/mach-omap2/temp_sensor_device.c @@ -0,0 +1,95 @@ +/* + * OMAP on die Temperature sensor device file + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Author: J Keerthy <j-keerthy@ti.com> + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <plat/omap_device.h> +#include "control.h" +#include "pm.h" +#include <plat/temperature_sensor.h> + +void omap_temp_sensor_resume_idle(void) +{ + omap_temp_sensor_idle(0); +} + +void omap_temp_sensor_prepare_idle(void) +{ + omap_temp_sensor_idle(1); +} + +static struct omap_device_pm_latency omap_temp_sensor_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + } +}; + +static int temp_sensor_dev_init(struct omap_hwmod *oh, void *user) +{ + struct omap_temp_sensor_pdata *temp_sensor_pdata; + struct omap_device *od; + static int i; + int ret = 0; + + temp_sensor_pdata = + kzalloc(sizeof(struct omap_temp_sensor_pdata), GFP_KERNEL); + if (!temp_sensor_pdata) { + pr_err + ("%s: Unable to allocate memory for %s.Error!\n", + __func__, oh->name); + return -ENOMEM; + } + + temp_sensor_pdata->offset = OMAP4_CTRL_MODULE_CORE_TEMP_SENSOR; + + temp_sensor_pdata->name = "omap_temp_sensor"; + + od = omap_device_build(temp_sensor_pdata->name, i, oh, temp_sensor_pdata, + sizeof(*temp_sensor_pdata), + omap_temp_sensor_latency, + ARRAY_SIZE(omap_temp_sensor_latency), 0); + if (IS_ERR(od)) { + pr_warning("%s: Could not build omap_device for %s: %s.\n\n", + __func__, temp_sensor_pdata->name, oh->name); + ret = -EINVAL; + goto done; + } + + i++; +done: + kfree(temp_sensor_pdata); + return ret; +} + +int __init omap_devinit_temp_sensor(void) +{ + if (!cpu_is_omap446x()) + return 0; + + return omap_hwmod_for_each_by_class("thermal_sensor", + temp_sensor_dev_init, NULL); +} + +arch_initcall(omap_devinit_temp_sensor); diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 3b9cf85..69a5e00 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -44,7 +44,7 @@ #include <plat/omap_hwmod.h> #include "timer-gp.h" - +#include "dmtimer.h" /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ #define MAX_GPTIMER_ID 12 @@ -106,6 +106,7 @@ static struct clock_event_device clockevent_gpt = { .name = "gp timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .shift = 32, + .rating = 300, .set_next_event = omap2_gp_timer_set_next_event, .set_mode = omap2_gp_timer_set_mode, }; @@ -134,13 +135,9 @@ static void __init omap2_gp_clockevent_init(void) { u32 tick_rate; int src; - char clockevent_hwmod_name[8]; /* 8 = sizeof("timerXX0") */ inited = 1; - sprintf(clockevent_hwmod_name, "timer%d", gptimer_id); - omap_hwmod_setup_one(clockevent_hwmod_name); - gptimer = omap_dm_timer_request_specific(gptimer_id); BUG_ON(gptimer == NULL); gptimer_wakeup = gptimer; @@ -154,8 +151,8 @@ static void __init omap2_gp_clockevent_init(void) #endif if (gptimer_id != 12) - WARN(IS_ERR_VALUE(omap_dm_timer_set_source(gptimer, src)), - "timer-gp: omap_dm_timer_set_source() failed\n"); + WARN(IS_ERR_VALUE(omap2_system_timer_set_src(gptimer, src)), + "timer-gp: omap2_system_timer_set_src() failed\n"); tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer)); @@ -174,7 +171,8 @@ static void __init omap2_gp_clockevent_init(void) clockevent_delta2ns(3, &clockevent_gpt); /* Timer internal resynch latency. */ - clockevent_gpt.cpumask = cpumask_of(0); + clockevent_gpt.cpumask = cpu_all_mask; + clockevent_gpt.irq = omap_dm_timer_get_irq(gptimer); clockevents_register_device(&clockevent_gpt); } @@ -255,7 +253,7 @@ static void __init omap2_gp_timer_init(void) BUG_ON(!twd_base); } #endif - omap_dm_timer_init(); + omap2_system_timer_init(gptimer_id); omap2_gp_clockevent_init(); omap2_gp_clocksource_init(); diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 89ae298..7b422b5 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -22,58 +22,433 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/dma-mapping.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> #include <asm/io.h> #include <mach/hardware.h> #include <mach/irqs.h> #include <plat/usb.h> +#include <plat/omap_device.h> #include "mux.h" #ifdef CONFIG_MFD_OMAP_USB_HOST -#define OMAP_USBHS_DEVICE "usbhs-omap" +#define OMAP_USBHS_DEVICE "usbhs_omap" +#define USBHS_UHH_HWMODNAME "usbhs_uhh" +#define USBHS_OHCI_HWMODNAME "usbhs_ohci" +#define USBHS_EHCI_HWMODNAME "usbhs_ehci" +#define USBHS_TLL_HWMODNAME "usbhs_tll" -static struct resource usbhs_resources[] = { +static struct usbhs_omap_platform_data usbhs_data; +static struct ehci_hcd_omap_platform_data ehci_data; +static struct ohci_hcd_omap_platform_data ohci_data; + +static struct omap_device_pm_latency omap_uhhtll_latency[] = { + { + .deactivate_func = omap_device_idle_hwmods, + .activate_func = omap_device_enable_hwmods, + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, + }, +}; + +static struct usbhs_wakeup { + struct device *dev; + struct omap_hwmod *oh_ehci; + struct omap_hwmod *oh_ohci; + struct work_struct wakeup_work; + int wakeup_ehci:1; + int wakeup_ohci:1; +} *usbhs_wake; + +/* MUX settings for EHCI pins */ +static struct omap_device_pad port1_phy_pads[] __initdata = { { - .name = "uhh", - .flags = IORESOURCE_MEM, + .name = "usbb1_ulpitll_stp.usbb1_ulpiphy_stp", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE4, }, { - .name = "tll", - .flags = IORESOURCE_MEM, + .name = "usbb1_ulpitll_clk.usbb1_ulpiphy_clk", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, }, { - .name = "ehci", - .flags = IORESOURCE_MEM, + .name = "usbb1_ulpitll_dir.usbb1_ulpiphy_dir", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~OMAP_WAKEUP_EN, + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, }, { - .name = "ehci-irq", - .flags = IORESOURCE_IRQ, + .name = "usbb1_ulpitll_nxt.usbb1_ulpiphy_nxt", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, }, { - .name = "ohci", - .flags = IORESOURCE_MEM, + .name = "usbb1_ulpitll_dat0.usbb1_ulpiphy_dat0", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~OMAP_WAKEUP_EN, + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, }, { - .name = "ohci-irq", - .flags = IORESOURCE_IRQ, - } + .name = "usbb1_ulpitll_dat1.usbb1_ulpiphy_dat1", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb1_ulpitll_dat2.usbb1_ulpiphy_dat2", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb1_ulpitll_dat3.usbb1_ulpiphy_dat3", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb1_ulpitll_dat4.usbb1_ulpiphy_dat4", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb1_ulpitll_dat5.usbb1_ulpiphy_dat5", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb1_ulpitll_dat6.usbb1_ulpiphy_dat6", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb1_ulpitll_dat7.usbb1_ulpiphy_dat7", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, }; -static struct platform_device usbhs_device = { - .name = OMAP_USBHS_DEVICE, - .id = 0, - .num_resources = ARRAY_SIZE(usbhs_resources), - .resource = usbhs_resources, +static struct omap_device_pad port1_tll_pads[] __initdata = { + { + .name = "usbb1_ulpitll_stp.usbb1_ulpitll_stp", + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_clk.usbb1_ulpitll_clk", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dir.usbb1_ulpitll_dir", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_nxt.usbb1_ulpitll_nxt", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dat0.usbb1_ulpitll_dat0", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dat1.usbb1_ulpitll_dat1", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dat2.usbb1_ulpitll_dat2", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dat3.usbb1_ulpitll_dat3", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dat4.usbb1_ulpitll_dat4", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dat5.usbb1_ulpitll_dat5", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dat6.usbb1_ulpitll_dat6", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb1_ulpitll_dat7.usbb1_ulpitll_dat7", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, }; -static struct usbhs_omap_platform_data usbhs_data; -static struct ehci_hcd_omap_platform_data ehci_data; -static struct ohci_hcd_omap_platform_data ohci_data; +static struct omap_device_pad port2_phy_pads[] __initdata = { + { + .name = "usbb2_ulpitll_stp.usbb2_ulpiphy_stp", + .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_clk.usbb2_ulpiphy_clk", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dir.usbb2_ulpiphy_dir", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_WAKEUP_EN + | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_nxt.usbb2_ulpiphy_nxt", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dat0.usbb2_ulpiphy_dat0", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_WAKEUP_EN + | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dat1.usbb2_ulpiphy_dat1", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dat2.usbb2_ulpiphy_dat2", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dat3.usbb2_ulpiphy_dat3", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dat4.usbb2_ulpiphy_dat4", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dat5.usbb2_ulpiphy_dat5", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dat6.usbb2_ulpiphy_dat6", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "usbb2_ulpitll_dat7.usbb2_ulpiphy_dat7", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, +}; -/* MUX settings for EHCI pins */ +static struct omap_device_pad port2_tll_pads[] __initdata = { + { + .name = "usbb2_ulpitll_stp.usbb2_ulpitll_stp", + .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_clk.usbb2_ulpitll_clk", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dir.usbb2_ulpitll_dir", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_nxt.usbb2_ulpitll_nxt", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dat0.usbb2_ulpitll_dat0", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dat1.usbb2_ulpitll_dat1", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dat2.usbb2_ulpitll_dat2", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dat3.usbb2_ulpitll_dat3", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dat4.usbb2_ulpitll_dat4", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dat5.usbb2_ulpitll_dat5", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dat6.usbb2_ulpitll_dat6", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, + { + .name = "usbb2_ulpitll_dat7.usbb2_ulpitll_dat7", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE0, + }, +}; + +static struct omap_device_pad port1_6pin_pads[] __initdata = { + { + .name = "usbb1_ulpitll_stp.usbb1_mm_rxdp", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_nxt.usbb1_mm_rxdm", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat0.usbb1_mm_rxrcv", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat3.usbb1_mm_txen", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat1.usbb1_mm_txdat", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat2.usbb1_mm_txse0", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, +}; + +static struct omap_device_pad port1_4pin_pads[] __initdata = { + { + .name = "usbb1_ulpitll_dat0.usbb1_mm_rxrcv", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat3.usbb1_mm_txen", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat1.usbb1_mm_txdat", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat2.usbb1_mm_txse0", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, +}; + +static struct omap_device_pad port1_3pin_pads[] __initdata = { + { + .name = "usbb1_ulpitll_dat3.usbb1_mm_txen", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat1.usbb1_mm_txdat", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat2.usbb1_mm_txse0", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, +}; + +static struct omap_device_pad port1_2pin_pads[] __initdata = { + { + .name = "usbb1_ulpitll_dat1.usbb1_mm_txdat", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, + { + .name = "usbb1_ulpitll_dat2.usbb1_mm_txse0", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE5, + }, +}; + +static struct omap_device_pad port2_6pin_pads[] __initdata = { + { + .name = "abe_mcbsp2_dr.usbb2_mm_rxdp", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_mcbsp2_clkx.usbb2_mm_rxdm", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_mcbsp2_dx.usbb2_mm_rxrcv", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_mcbsp2_fsx.usbb2_mm_txen", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_dmic_din1.usbb2_mm_txdat", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_dmic_clk1.usbb2_mm_txse0", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = (OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4) & ~(OMAP_WAKEUP_EN), + .idle = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, +}; + +static struct omap_device_pad port2_4pin_pads[] __initdata = { + { + .name = "abe_mcbsp2_dx.usbb2_mm_rxrcv", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_mcbsp2_fsx.usbb2_mm_txen", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_dmic_din1.usbb2_mm_txdat", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_dmic_clk1.usbb2_mm_txse0", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, +}; + +static struct omap_device_pad port2_3pin_pads[] __initdata = { + { + .name = "abe_mcbsp2_fsx.usbb2_mm_txen", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_dmic_din1.usbb2_mm_txdat", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_dmic_clk1.usbb2_mm_txse0", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, +}; + +static struct omap_device_pad port2_2pin_pads[] __initdata = { + { + .name = "abe_mcbsp2_fsx.usbb2_mm_txen", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_dmic_din1.usbb2_mm_txdat", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, + { + .name = "abe_dmic_clk1.usbb2_mm_txse0", + .enable = OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE4, + }, +}; /* * setup_ehci_io_mux - initialize IO pad mux for USBHOST */ @@ -220,60 +595,20 @@ static void setup_ehci_io_mux(const enum usbhs_omap_port_mode *port_mode) return; } -static void setup_4430ehci_io_mux(const enum usbhs_omap_port_mode *port_mode) +static struct omap_hwmod_mux_info * +setup_4430ehci_io_mux(const enum usbhs_omap_port_mode *port_mode) { + struct omap_device_pad *pads; + int pads_cnt; + switch (port_mode[0]) { case OMAP_EHCI_PORT_MODE_PHY: - omap_mux_init_signal("usbb1_ulpiphy_stp", - OMAP_PIN_OUTPUT); - omap_mux_init_signal("usbb1_ulpiphy_clk", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dir", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_nxt", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dat0", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dat1", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dat2", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dat3", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dat4", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dat5", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dat6", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpiphy_dat7", - OMAP_PIN_INPUT_PULLDOWN); + pads = port1_phy_pads; + pads_cnt = ARRAY_SIZE(port1_phy_pads); break; case OMAP_EHCI_PORT_MODE_TLL: - omap_mux_init_signal("usbb1_ulpitll_stp", - OMAP_PIN_INPUT_PULLUP); - omap_mux_init_signal("usbb1_ulpitll_clk", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dir", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_nxt", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dat0", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dat1", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dat2", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dat3", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dat4", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dat5", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dat6", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_ulpitll_dat7", - OMAP_PIN_INPUT_PULLDOWN); + pads = port1_tll_pads; + pads_cnt = ARRAY_SIZE(port1_tll_pads); break; case OMAP_USBHS_PORT_MODE_UNUSED: default: @@ -281,61 +616,19 @@ static void setup_4430ehci_io_mux(const enum usbhs_omap_port_mode *port_mode) } switch (port_mode[1]) { case OMAP_EHCI_PORT_MODE_PHY: - omap_mux_init_signal("usbb2_ulpiphy_stp", - OMAP_PIN_OUTPUT); - omap_mux_init_signal("usbb2_ulpiphy_clk", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dir", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_nxt", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dat0", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dat1", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dat2", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dat3", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dat4", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dat5", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dat6", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpiphy_dat7", - OMAP_PIN_INPUT_PULLDOWN); + pads = port2_phy_pads; + pads_cnt = ARRAY_SIZE(port2_phy_pads); break; case OMAP_EHCI_PORT_MODE_TLL: - omap_mux_init_signal("usbb2_ulpitll_stp", - OMAP_PIN_INPUT_PULLUP); - omap_mux_init_signal("usbb2_ulpitll_clk", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dir", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_nxt", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dat0", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dat1", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dat2", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dat3", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dat4", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dat5", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dat6", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_ulpitll_dat7", - OMAP_PIN_INPUT_PULLDOWN); + pads = port2_tll_pads; + pads_cnt = ARRAY_SIZE(port2_tll_pads); break; case OMAP_USBHS_PORT_MODE_UNUSED: default: break; } + + return omap_hwmod_mux_init(pads, pads_cnt); } static void setup_ohci_io_mux(const enum usbhs_omap_port_mode *port_mode) @@ -435,37 +728,35 @@ static void setup_ohci_io_mux(const enum usbhs_omap_port_mode *port_mode) } } -static void setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode) +static struct omap_hwmod_mux_info * +setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode) { + struct omap_device_pad *pads; + int pads_cnt; + switch (port_mode[0]) { case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: - omap_mux_init_signal("usbb1_mm_rxdp", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_mm_rxdm", - OMAP_PIN_INPUT_PULLDOWN); - + pads = port1_6pin_pads; + pads_cnt = ARRAY_SIZE(port1_6pin_pads); + break; case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: - omap_mux_init_signal("usbb1_mm_rxrcv", - OMAP_PIN_INPUT_PULLDOWN); - + pads = port1_4pin_pads; + pads_cnt = ARRAY_SIZE(port1_4pin_pads); + break; case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: - omap_mux_init_signal("usbb1_mm_txen", - OMAP_PIN_INPUT_PULLDOWN); - - + pads = port1_3pin_pads; + pads_cnt = ARRAY_SIZE(port1_3pin_pads); + break; case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: - omap_mux_init_signal("usbb1_mm_txdat", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb1_mm_txse0", - OMAP_PIN_INPUT_PULLDOWN); + pads = port1_2pin_pads; + pads_cnt = ARRAY_SIZE(port1_2pin_pads); break; - case OMAP_USBHS_PORT_MODE_UNUSED: default: break; @@ -476,39 +767,79 @@ static void setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode) case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: - omap_mux_init_signal("usbb2_mm_rxdp", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_mm_rxdm", - OMAP_PIN_INPUT_PULLDOWN); - + pads = port2_6pin_pads; + pads_cnt = ARRAY_SIZE(port2_6pin_pads); + break; case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: - omap_mux_init_signal("usbb2_mm_rxrcv", - OMAP_PIN_INPUT_PULLDOWN); - + pads = port2_4pin_pads; + pads_cnt = ARRAY_SIZE(port2_4pin_pads); + break; case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: - omap_mux_init_signal("usbb2_mm_txen", - OMAP_PIN_INPUT_PULLDOWN); - - + pads = port2_3pin_pads; + pads_cnt = ARRAY_SIZE(port2_3pin_pads); + break; case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: - omap_mux_init_signal("usbb2_mm_txdat", - OMAP_PIN_INPUT_PULLDOWN); - omap_mux_init_signal("usbb2_mm_txse0", - OMAP_PIN_INPUT_PULLDOWN); + pads = port2_2pin_pads; + pads_cnt = ARRAY_SIZE(port2_3pin_pads); break; - case OMAP_USBHS_PORT_MODE_UNUSED: default: break; } + + return omap_hwmod_mux_init(pads, pads_cnt); +} + +void usbhs_wakeup() +{ + int workq = 0; + + if (!usbhs_wake) + return; + + if (test_bit(USB_OHCI_LOADED, &usb_hcds_loaded) && + omap_hwmod_pad_get_wakeup_status(usbhs_wake->oh_ohci)) { + usbhs_wake->wakeup_ohci = 1; + workq = 1; + } + + if (test_bit(USB_EHCI_LOADED, &usb_hcds_loaded) && + omap_hwmod_pad_get_wakeup_status(usbhs_wake->oh_ehci)) { + usbhs_wake->wakeup_ehci = 1; + workq = 1; + } + + if (workq) + queue_work(pm_wq, &usbhs_wake->wakeup_work); +} + +static void usbhs_resume_work(struct work_struct *work) +{ + dev_dbg(usbhs_wake->dev, "USB IO PAD Wakeup event triggered\n"); + + if (usbhs_wake->wakeup_ehci) { + usbhs_wake->wakeup_ehci = 0; + omap_hwmod_disable_ioring_wakeup(usbhs_wake->oh_ehci); + } + + if (usbhs_wake->wakeup_ohci) { + usbhs_wake->wakeup_ohci = 0; + omap_hwmod_disable_ioring_wakeup(usbhs_wake->oh_ohci); + } + + pm_runtime_get_sync(usbhs_wake->dev); + pm_runtime_put_sync(usbhs_wake->dev); } void __init usbhs_init(const struct usbhs_omap_board_data *pdata) { - int i; + struct omap_hwmod *oh[4]; + struct omap_device *od; + int bus_id = -1; + int i; for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { usbhs_data.port_mode[i] = pdata->port_mode[i]; @@ -516,55 +847,74 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) ehci_data.port_mode[i] = pdata->port_mode[i]; ehci_data.reset_gpio_port[i] = pdata->reset_gpio_port[i]; ehci_data.regulator[i] = pdata->regulator[i]; + ehci_data.transceiver_clk[i] = pdata->transceiver_clk[i]; } ehci_data.phy_reset = pdata->phy_reset; ohci_data.es2_compatibility = pdata->es2_compatibility; usbhs_data.ehci_data = &ehci_data; usbhs_data.ohci_data = &ohci_data; + oh[0] = omap_hwmod_lookup(USBHS_UHH_HWMODNAME); + if (!oh[0]) { + pr_err("Could not look up %s\n", USBHS_UHH_HWMODNAME); + return; + } + + oh[1] = omap_hwmod_lookup(USBHS_OHCI_HWMODNAME); + if (!oh[1]) { + pr_err("Could not look up %s\n", USBHS_OHCI_HWMODNAME); + return; + } + + oh[2] = omap_hwmod_lookup(USBHS_EHCI_HWMODNAME); + if (!oh[2]) { + pr_err("Could not look up %s\n", USBHS_EHCI_HWMODNAME); + return; + } + + oh[3] = omap_hwmod_lookup(USBHS_TLL_HWMODNAME); + if (!oh[3]) { + pr_err("Could not look up %s\n", USBHS_TLL_HWMODNAME); + return; + } + if (cpu_is_omap34xx()) { - usbhs_resources[0].start = OMAP34XX_UHH_CONFIG_BASE; - usbhs_resources[0].end = OMAP34XX_UHH_CONFIG_BASE + SZ_1K - 1; - usbhs_resources[1].start = OMAP34XX_USBTLL_BASE; - usbhs_resources[1].end = OMAP34XX_USBTLL_BASE + SZ_4K - 1; - usbhs_resources[2].start = OMAP34XX_EHCI_BASE; - usbhs_resources[2].end = OMAP34XX_EHCI_BASE + SZ_1K - 1; - usbhs_resources[3].start = INT_34XX_EHCI_IRQ; - usbhs_resources[4].start = OMAP34XX_OHCI_BASE; - usbhs_resources[4].end = OMAP34XX_OHCI_BASE + SZ_1K - 1; - usbhs_resources[5].start = INT_34XX_OHCI_IRQ; setup_ehci_io_mux(pdata->port_mode); setup_ohci_io_mux(pdata->port_mode); } else if (cpu_is_omap44xx()) { - usbhs_resources[0].start = OMAP44XX_UHH_CONFIG_BASE; - usbhs_resources[0].end = OMAP44XX_UHH_CONFIG_BASE + SZ_1K - 1; - usbhs_resources[1].start = OMAP44XX_USBTLL_BASE; - usbhs_resources[1].end = OMAP44XX_USBTLL_BASE + SZ_4K - 1; - usbhs_resources[2].start = OMAP44XX_HSUSB_EHCI_BASE; - usbhs_resources[2].end = OMAP44XX_HSUSB_EHCI_BASE + SZ_1K - 1; - usbhs_resources[3].start = OMAP44XX_IRQ_EHCI; - usbhs_resources[4].start = OMAP44XX_HSUSB_OHCI_BASE; - usbhs_resources[4].end = OMAP44XX_HSUSB_OHCI_BASE + SZ_1K - 1; - usbhs_resources[5].start = OMAP44XX_IRQ_OHCI; - setup_4430ehci_io_mux(pdata->port_mode); - setup_4430ohci_io_mux(pdata->port_mode); + oh[2]->mux = setup_4430ehci_io_mux(pdata->port_mode); + oh[1]->mux = setup_4430ohci_io_mux(pdata->port_mode); } - if (platform_device_add_data(&usbhs_device, - &usbhs_data, sizeof(usbhs_data)) < 0) { - printk(KERN_ERR "USBHS platform_device_add_data failed\n"); - goto init_end; + od = omap_device_build_ss(OMAP_USBHS_DEVICE, bus_id, oh, 4, + (void *)&usbhs_data, sizeof(usbhs_data), + omap_uhhtll_latency, + ARRAY_SIZE(omap_uhhtll_latency), false); + + if (IS_ERR(od)) { + pr_err("Could not build hwmod devices %s, %s\n", + USBHS_UHH_HWMODNAME, USBHS_TLL_HWMODNAME); + return; } - if (platform_device_register(&usbhs_device) < 0) - printk(KERN_ERR "USBHS platform_device_register failed\n"); + usbhs_wake = kmalloc(sizeof(*usbhs_wake), GFP_KERNEL); + if (!usbhs_wake) { + pr_err("Could not allocate usbhs_wake\n"); + return; + } -init_end: - return; + INIT_WORK(&usbhs_wake->wakeup_work, usbhs_resume_work); + usbhs_wake->oh_ehci = oh[2]; + usbhs_wake->oh_ohci = oh[1]; + usbhs_wake->dev = &od->pdev.dev; } #else +void usbhs_wakeup() +{ +} + void __init usbhs_init(const struct usbhs_omap_board_data *pdata) { } diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index c7ed540..bd3b513 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -119,7 +119,7 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data) struct omap_hwmod *oh; struct omap_device *od; struct platform_device *pdev; - struct device *dev; + struct device *dev = NULL; int bus_id = -1; const char *oh_name, *name; struct omap_musb_board_data *board_data; @@ -140,7 +140,7 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data) musb_plat.extvbus = board_data->extvbus; if (cpu_is_omap44xx()) - omap4430_phy_init(dev); + omap4430_phy_init(dev); /* power down the phy */ if (cpu_is_omap3517() || cpu_is_omap3505()) { oh_name = "am35x_otg_hs"; diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c new file mode 100644 index 0000000..42ffc64 --- /dev/null +++ b/arch/arm/mach-omap2/vc.c @@ -0,0 +1,636 @@ +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/clk.h> + +#include <plat/cpu.h> + +#include "voltage.h" +#include "vc.h" +#include "prm-regbits-34xx.h" +#include "prm-regbits-44xx.h" +#include "prm44xx.h" + +#define OMAP_VC_I2C_ACK_DELAY 3 + +/** + * struct omap_vc_channel_cfg - describe the cfg_channel bitfield + * @sa: bit for slave address + * @rav: bit for voltage configuration register + * @rac: bit for command configuration register + * @racen: enable bit for RAC + * @cmd: bit for command value set selection + * + * Channel configuration bits, common for OMAP3+ + * OMAP3 register: PRM_VC_CH_CONF + * OMAP4 register: PRM_VC_CFG_CHANNEL + * OMAP5 register: PRM_VC_SMPS_<voltdm>_CONFIG + */ +struct omap_vc_channel_cfg { + u8 sa; + u8 rav; + u8 rac; + u8 racen; + u8 cmd; +}; + +static struct omap_vc_channel_cfg vc_default_channel_cfg = { + .sa = BIT(0), + .rav = BIT(1), + .rac = BIT(2), + .racen = BIT(3), + .cmd = BIT(4), +}; + +/* + * On OMAP3+, all VC channels have the above default bitfield + * configuration, except the OMAP4 MPU channel. This appears + * to be a freak accident as every other VC channel has the + * default configuration, thus creating a mutant channel config. + */ +static struct omap_vc_channel_cfg vc_mutant_channel_cfg = { + .sa = BIT(0), + .rav = BIT(2), + .rac = BIT(3), + .racen = BIT(4), + .cmd = BIT(1), +}; + +static struct omap_vc_channel_cfg *vc_cfg_bits; +#define CFG_CHANNEL_MASK 0x1f + +/** + * omap_vc_config_channel - configure VC channel to PMIC mappings + * @voltdm: pointer to voltagdomain defining the desired VC channel + * + * Configures the VC channel to PMIC mappings for the following + * PMIC settings + * - i2c slave address (SA) + * - voltage configuration address (RAV) + * - command configuration address (RAC) and enable bit (RACEN) + * - command values for ON, ONLP, RET and OFF (CMD) + * + * This function currently only allows flexible configuration of the + * non-default channel. Starting with OMAP4, there are more than 2 + * channels, with one defined as the default (on OMAP4, it's MPU.) + * Only the non-default channel can be configured. + */ +static int omap_vc_config_channel(struct voltagedomain *voltdm) +{ + struct omap_vc_channel *vc = voltdm->vc; + + /* + * For default channel, the only configurable bit is RACEN. + * All others must stay at zero (see function comment above.) + */ + if (vc->flags & OMAP_VC_CHANNEL_DEFAULT) + vc->cfg_channel &= vc_cfg_bits->racen; + + voltdm->rmw(CFG_CHANNEL_MASK << vc->cfg_channel_sa_shift, + vc->cfg_channel << vc->cfg_channel_sa_shift, + vc->common->cfg_channel_reg); + + return 0; +} + +/* Voltage scale and accessory APIs */ +int omap_vc_pre_scale(struct voltagedomain *voltdm, + unsigned long target_volt, + struct omap_volt_data *target_v, + u8 *target_vsel, u8 *current_vsel) +{ + struct omap_vc_channel *vc = voltdm->vc; + u32 vc_cmdval; + + /* Check if sufficient pmic info is available for this vdd */ + if (!voltdm->pmic) { + pr_err("%s: Insufficient pmic info to scale the vdd_%s\n", + __func__, voltdm->name); + return -EINVAL; + } + + if (!voltdm->pmic->uv_to_vsel) { + pr_err("%s: PMIC function to convert voltage in uV to" + "vsel not registered. Hence unable to scale voltage" + "for vdd_%s\n", __func__, voltdm->name); + return -ENODATA; + } + + if (!voltdm->read || !voltdm->write) { + pr_err("%s: No read/write API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return -EINVAL; + } + + *target_vsel = voltdm->pmic->uv_to_vsel(target_volt); + *current_vsel = voltdm->read(voltdm->vp->voltage); + + /* Setting the ON voltage to the new target voltage */ + vc_cmdval = voltdm->read(vc->cmdval_reg); + vc_cmdval &= ~vc->common->cmd_on_mask; + vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift); + voltdm->write(vc_cmdval, vc->cmdval_reg); + + omap_vp_update_errorgain(voltdm, target_v); + + return 0; +} + +/** + * omap_vc_set_auto_trans() - set auto transition parameters for a domain + * @voltdm: voltage domain we are interested in + * @flag: which state should we program this to + */ +int omap_vc_set_auto_trans(struct voltagedomain *voltdm, u8 flag) +{ + struct omap_vc_channel *vc; + const struct omap_vc_auto_trans *auto_trans; + u8 val = OMAP_VC_CHANNEL_AUTO_TRANSITION_UNSUPPORTED; + + if (!voltdm) { + pr_err("%s: NULL Voltage domain!\n", __func__); + return -ENOENT; + } + vc = voltdm->vc; + if (!vc) { + pr_err("%s: NULL VC Voltage domain %s!\n", __func__, + voltdm->name); + return -ENOENT; + } + + auto_trans = vc->auto_trans; + if (!auto_trans) { + pr_debug("%s: No auto trans %s!\n", __func__, voltdm->name); + return 0; + } + + /* Handle value and masks per silicon data */ + switch (flag) { + case OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE: + val = 0x0; + break; + case OMAP_VC_CHANNEL_AUTO_TRANSITION_SLEEP: + val = auto_trans->sleep_val; + break; + case OMAP_VC_CHANNEL_AUTO_TRANSITION_RETENTION: + val = auto_trans->retention_val; + break; + case OMAP_VC_CHANNEL_AUTO_TRANSITION_OFF: + val = auto_trans->off_val; + break; + default: + pr_err("%s: Voltdm %s invalid flag %d\n", __func__, + voltdm->name, flag); + return -EINVAL; + } + + if (val == OMAP_VC_CHANNEL_AUTO_TRANSITION_UNSUPPORTED) { + pr_err("%s: transition to %d on %s is NOT supported\n", + __func__, flag, voltdm->name); + return -EINVAL; + } + + /* All ready - set it and move on.. */ + voltdm->rmw(vc->auto_trans_mask, val << __ffs(vc->auto_trans_mask), + auto_trans->reg); + return 0; +} + +void omap_vc_post_scale(struct voltagedomain *voltdm, + unsigned long target_volt, + struct omap_volt_data *target_vdata, + u8 target_vsel, u8 current_vsel) +{ + struct omap_vc_channel *vc; + u32 smps_steps = 0, smps_delay = 0; + u8 on_vsel, onlp_vsel; + u32 val; + + if (IS_ERR_OR_NULL(voltdm)) { + pr_err("%s bad voldm\n", __func__); + return; + } + + vc = voltdm->vc; + if (IS_ERR_OR_NULL(vc)) { + pr_err("%s voldm=%s bad vc\n", __func__, voltdm->name); + return; + } + + smps_steps = abs(target_vsel - current_vsel); + /* SMPS slew rate / step size. 2us added as buffer. */ + smps_delay = ((smps_steps * voltdm->pmic->step_size) / + voltdm->pmic->slew_rate) + 2; + udelay(smps_delay); + + voltdm->curr_volt = target_vdata; + + /* Set up the on voltage for wakeup from lp and OFF */ + on_vsel = voltdm->pmic->uv_to_vsel(target_volt); + onlp_vsel = voltdm->pmic->uv_to_vsel(target_volt); + val = (on_vsel << vc->common->cmd_on_shift) | + (onlp_vsel << vc->common->cmd_onlp_shift) | + vc->setup_voltage_common; + voltdm->write(val, vc->cmdval_reg); +} + +static int omap_vc_bypass_send_value(struct voltagedomain *voltdm, + struct omap_vc_channel *vc, u8 sa, u8 reg, u32 data) +{ + u32 loop_cnt = 0, retries_cnt = 0; + u32 vc_valid, vc_bypass_val_reg, vc_bypass_value; + + if (IS_ERR_OR_NULL(vc->common)) { + pr_err("%s voldm=%s bad value for vc->common\n", + __func__, voltdm->name); + return -EINVAL; + } + + vc_valid = vc->common->valid; + vc_bypass_val_reg = vc->common->bypass_val_reg; + vc_bypass_value = (data << vc->common->data_shift) | + (reg << vc->common->regaddr_shift) | + (sa << vc->common->slaveaddr_shift); + + voltdm->write(vc_bypass_value, vc_bypass_val_reg); + voltdm->write(vc_bypass_value | vc_valid, vc_bypass_val_reg); + + vc_bypass_value = voltdm->read(vc_bypass_val_reg); + /* + * Loop till the bypass command is acknowledged from the SMPS. + * NOTE: This is legacy code. The loop count and retry count needs + * to be revisited. + */ + while (vc_bypass_value & vc_valid) { + loop_cnt++; + + if (retries_cnt > 10) { + pr_warning("%s: Retry count exceeded\n", __func__); + return -ETIMEDOUT; + } + + if (loop_cnt > 50) { + retries_cnt++; + loop_cnt = 0; + udelay(10); + } + vc_bypass_value = voltdm->read(vc_bypass_val_reg); + } + + return 0; + +} + +/* vc_bypass_scale_voltage - VC bypass method of voltage scaling */ +int omap_vc_bypass_scale_voltage(struct voltagedomain *voltdm, + struct omap_volt_data *target_v) +{ + struct omap_vc_channel *vc; + u8 target_vsel, current_vsel; + int ret; + unsigned long target_volt = omap_get_operation_voltage(target_v); + + if (IS_ERR_OR_NULL(voltdm)) { + pr_err("%s bad voldm\n", __func__); + return -EINVAL; + } + + vc = voltdm->vc; + if (IS_ERR_OR_NULL(vc)) { + pr_err("%s voldm=%s bad vc\n", __func__, voltdm->name); + return -EINVAL; + } + + ret = omap_vc_pre_scale(voltdm, target_volt, target_v, &target_vsel, + ¤t_vsel); + if (ret) + return ret; + + ret = omap_vc_bypass_send_value(voltdm, vc, vc->i2c_slave_addr, + vc->volt_reg_addr, target_vsel); + if (ret) + return ret; + + omap_vc_post_scale(voltdm, target_volt, target_v, target_vsel, + current_vsel); + return 0; +} + +/** + * omap_vc_bypass_send_i2c_msg() - Function to control PMIC registers over SRI2C + * @voltdm: voltage domain + * @slave_addr: slave address of the device. + * @reg_addr: register address to access + * @data: what do we want to write there + * + * Many simpler PMICs with a single I2C interface still have configuration + * registers that may need population. Typical being slew rate configurations + * thermal shutdown configuration etc. When these PMICs are hooked on I2C_SR, + * this function allows these configuration registers to be accessed. + * + * WARNING: Though this could be used for voltage register configurations over + * I2C_SR, DONOT use it for that purpose, all the Voltage controller's internal + * information is bypassed using this function and must be used judiciously. + */ +int omap_vc_bypass_send_i2c_msg(struct voltagedomain *voltdm, u8 slave_addr, + u8 reg_addr, u8 data) +{ + struct omap_vc_channel *vc; + + if (IS_ERR_OR_NULL(voltdm)) { + pr_err("%s bad voldm\n", __func__); + return -EINVAL; + } + + vc = voltdm->vc; + if (IS_ERR_OR_NULL(vc)) { + pr_err("%s voldm=%s bad vc\n", __func__, voltdm->name); + return -EINVAL; + } + + return omap_vc_bypass_send_value(voltdm, vc, slave_addr, + reg_addr, data); +} + +static void __init omap3_vfsm_init(struct voltagedomain *voltdm) +{ + /* + * Voltage Manager FSM parameters init + * XXX This data should be passed in from the board file + */ + voltdm->write(OMAP3_CLKSETUP, OMAP3_PRM_CLKSETUP_OFFSET); + voltdm->write(OMAP3_VOLTOFFSET, OMAP3_PRM_VOLTOFFSET_OFFSET); + voltdm->write(OMAP3_VOLTSETUP2, OMAP3_PRM_VOLTSETUP2_OFFSET); +} + +static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) +{ + static bool is_initialized; + + if (is_initialized) + return; + + omap3_vfsm_init(voltdm); + + is_initialized = true; +} + + +/* OMAP4 specific voltage init functions */ +static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) +{ + static bool is_initialized; + struct omap_voltdm_pmic *pmic = voltdm->pmic; + u32 vc_val = 0; + + if (is_initialized) + return; + + if (pmic->i2c_high_speed) { + vc_val |= pmic->i2c_hscll_low << OMAP4430_HSCLL_SHIFT; + vc_val |= pmic->i2c_hscll_high << OMAP4430_HSCLH_SHIFT; + } + + vc_val |= pmic->i2c_scll_low << OMAP4430_SCLL_SHIFT; + vc_val |= pmic->i2c_scll_high << OMAP4430_SCLH_SHIFT; + + if (vc_val) + voltdm->write(vc_val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); + + is_initialized = true; +} + +/** + * omap_vc_i2c_init - initialize I2C interface to PMIC + * @voltdm: voltage domain containing VC data + * + * Use PMIC supplied seetings for I2C high-speed mode and + * master code (if set) and program the VC I2C configuration + * register. + * + * The VC I2C configuration is common to all VC channels, + * so this function only configures I2C for the first VC + * channel registers. All other VC channels will use the + * same configuration. + */ +static void __init omap_vc_i2c_init(struct voltagedomain *voltdm) +{ + struct omap_vc_channel *vc = voltdm->vc; + static bool initialized; + static bool i2c_high_speed; + u8 mcode; + + if (initialized) { + if (voltdm->pmic->i2c_high_speed != i2c_high_speed) + pr_warn("%s: I2C config for all channels must match.", + __func__); + return; + } + + i2c_high_speed = voltdm->pmic->i2c_high_speed; + if (i2c_high_speed) + voltdm->rmw(vc->common->i2c_cfg_hsen_mask, + vc->common->i2c_cfg_hsen_mask, + vc->common->i2c_cfg_reg); + + mcode = voltdm->pmic->i2c_mcode; + if (mcode) + voltdm->rmw(vc->common->i2c_mcode_mask, + mcode << __ffs(vc->common->i2c_mcode_mask), + vc->common->i2c_cfg_reg); + + initialized = true; +} + +/** + * omap_vc_setup_lp_time() - configure the voltage ramp time for low states. + * @voltdm: voltagedomain we are interested in. + * @is_retention: Are we interested in retention or OFF? + * + * The ramp times are calculated based on the worst case voltage drop, + * which is the difference of on_volt and the ret_volt. This time is used + * for computing the duration necessary for low power states such as retention. + */ +static int __init omap_vc_setup_lp_time(struct voltagedomain *voltdm, + bool is_retention) +{ + u32 volt_drop = 0, volt_ramptime = 0, volt_rampcount; + u32 sys_clk_mhz = 0, sysclk_cycles = 0, max_latency_for_prescaler = 0; + struct clk *sys_ck; + u8 pre_scaler = 0; + struct omap_voltdm_pmic *pmic = voltdm->pmic; + struct omap_vc_channel *vc = voltdm->vc; + const struct setup_time_ramp_params *params; + + params = vc->common->setup_time_params; + /* If the VC data does not have params for us, return PMIC's value */ + if (!params) + return pmic->volt_setup_time; + if (!params->pre_scaler_to_sysclk_cycles_count) + return pmic->volt_setup_time; + + /* No of sys_clk cycles for pre_scaler 0 */ + sysclk_cycles = params->pre_scaler_to_sysclk_cycles[0]; + + sys_ck = clk_get(NULL, "sys_clkin_ck"); + if (IS_ERR_OR_NULL(sys_ck)) { + WARN_ONCE(1, "%s: unable to get sys_clkin_ck (voldm %s)\n", + __func__, voltdm->name); + return pmic->volt_setup_time; + } + sys_clk_mhz = clk_get_rate(sys_ck) / 1000000; + clk_put(sys_ck); + + /* + * If we chose prescaler 0x0, then we have a limit on the maximum + * latency for which we can chose a correct count. This is because, + * the count field is limited to 6 bits and max value can be 63 and + * for prescaler 0, ramp up/down counter is incremented every + * 64 system clock cycles. + * for eg, max latency for prescaler for 38.4Mhz sys clk would be + * 105 = (63 * 64) / 38.4 + */ + max_latency_for_prescaler = (63 * sysclk_cycles) / sys_clk_mhz; + + if (is_retention) + volt_drop = pmic->on_volt - pmic->ret_volt; + else + volt_drop = pmic->on_volt; + volt_ramptime = DIV_ROUND_UP(volt_drop, pmic->slew_rate); + volt_ramptime += OMAP_VC_I2C_ACK_DELAY; + + /* many PMICs need additional time to switch back on */ + if (!is_retention) + volt_ramptime += pmic->switch_on_time; + + if (volt_ramptime < max_latency_for_prescaler) + pre_scaler = 0x0; + else + pre_scaler = 0x1; + + /* + * IF we mess up values, then try to have some form of recovery using + * PMIC's value. + */ + if (pre_scaler > params->pre_scaler_to_sysclk_cycles_count) { + pr_err("%s: prescaler idx %d > available %d on domain %s\n", + __func__, pre_scaler, + params->pre_scaler_to_sysclk_cycles_count, voltdm->name); + return pmic->volt_setup_time; + } + + sysclk_cycles = params->pre_scaler_to_sysclk_cycles[pre_scaler]; + + volt_rampcount = ((volt_ramptime * sys_clk_mhz) / sysclk_cycles) + 1; + + return (pre_scaler << OMAP4430_RAMP_DOWN_PRESCAL_SHIFT) | + (pre_scaler << OMAP4430_RAMP_UP_PRESCAL_SHIFT) | + (volt_rampcount << OMAP4430_RAMP_DOWN_COUNT_SHIFT) | + (volt_rampcount << OMAP4430_RAMP_UP_COUNT_SHIFT); +} + +void __init omap_vc_init_channel(struct voltagedomain *voltdm) +{ + struct omap_vc_channel *vc = voltdm->vc; + u8 on_vsel, onlp_vsel, ret_vsel, off_vsel; + u32 val; + + if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) { + pr_err("%s: PMIC info requried to configure vc for" + "vdd_%s not populated.Hence cannot initialize vc\n", + __func__, voltdm->name); + return; + } + + if (!voltdm->read || !voltdm->write) { + pr_err("%s: No read/write API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + vc->cfg_channel = 0; + if (vc->flags & OMAP_VC_CHANNEL_CFG_MUTANT) + vc_cfg_bits = &vc_mutant_channel_cfg; + else + vc_cfg_bits = &vc_default_channel_cfg; + + /* get PMIC/board specific settings */ + vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr; + vc->volt_reg_addr = voltdm->pmic->volt_reg_addr; + vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr; + /* Calculate the RET voltage setup time and update volt_setup_time */ + vc->setup_time = omap_vc_setup_lp_time(voltdm, true); + + if ((vc->flags & OMAP_VC_CHANNEL_DEFAULT) && + ((vc->i2c_slave_addr == USE_DEFAULT_CHANNEL_I2C_PARAM) || + (vc->cmd_reg_addr == USE_DEFAULT_CHANNEL_I2C_PARAM) || + (vc->volt_reg_addr == USE_DEFAULT_CHANNEL_I2C_PARAM))) { + pr_err("%s: voltdm %s: default channel " + "bad config-sa=%2x vol=%2x, cmd=%2x?\n", __func__, + voltdm->name, vc->i2c_slave_addr, vc->volt_reg_addr, + vc->cmd_reg_addr); + return; + } + + /* Configure the i2c slave address for this VC */ + if (vc->i2c_slave_addr != USE_DEFAULT_CHANNEL_I2C_PARAM) { + voltdm->rmw(vc->smps_sa_mask, + vc->i2c_slave_addr << __ffs(vc->smps_sa_mask), + vc->common->smps_sa_reg); + vc->cfg_channel |= vc_cfg_bits->sa; + } + + /* + * Configure the PMIC register addresses. + */ + if (vc->volt_reg_addr != USE_DEFAULT_CHANNEL_I2C_PARAM) { + voltdm->rmw(vc->smps_volra_mask, + vc->volt_reg_addr << __ffs(vc->smps_volra_mask), + vc->common->smps_volra_reg); + vc->cfg_channel |= vc_cfg_bits->rav; + } + + if (vc->cmd_reg_addr != USE_DEFAULT_CHANNEL_I2C_PARAM) { + voltdm->rmw(vc->smps_cmdra_mask, + vc->cmd_reg_addr << __ffs(vc->smps_cmdra_mask), + vc->common->smps_cmdra_reg); + vc->cfg_channel |= vc_cfg_bits->rac; + } + + /* If voltage and cmd regs are same, we can use cmdra register */ + if (vc->volt_reg_addr == vc->cmd_reg_addr) + vc->cfg_channel |= vc_cfg_bits->racen; + + /* Set up the on, inactive, retention and off voltage */ + on_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->on_volt); + onlp_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->onlp_volt); + ret_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->ret_volt); + off_vsel = voltdm->pmic->uv_to_vsel(voltdm->pmic->off_volt); + vc->setup_voltage_common = + (ret_vsel << vc->common->cmd_ret_shift) | + (off_vsel << vc->common->cmd_off_shift); + val = (on_vsel << vc->common->cmd_on_shift) | + (onlp_vsel << vc->common->cmd_onlp_shift) | + vc->setup_voltage_common; + voltdm->write(val, vc->cmdval_reg); + vc->cfg_channel |= vc_cfg_bits->cmd; + + /* Channel configuration */ + omap_vc_config_channel(voltdm); + + /* Configure the setup times */ + voltdm->rmw(voltdm->vfsm->voltsetup_mask, + vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask), + voltdm->vfsm->voltsetup_reg); + voltdm->rmw(voltdm->vfsm->voltsetup_mask, + omap_vc_setup_lp_time(voltdm, false) << + ffs(voltdm->vfsm->voltsetup_mask), + voltdm->vfsm->voltsetupoff_reg); + + omap_vc_i2c_init(voltdm); + + if (cpu_is_omap34xx()) + omap3_vc_init_channel(voltdm); + else if (cpu_is_omap44xx()) + omap4_vc_init_channel(voltdm); +} diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index e776777..66c6d9a 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h @@ -19,8 +19,26 @@ #include <linux/kernel.h> +struct voltagedomain; + +/** + * struct setup_time_ramp_params - ramp time parameters + * @pre_scaler_to_sysclk_cycles: The array represents correlation of prescaler + * to the number of system clock cycles, for which rampdown counter is + * incremented or decremented in PRM_VOLTSETUP_XXX_RET_SLEEP registers. + * This is to handle variances in defined values due to conditions such + * as "Errata Id: i623: Retention/Sleep Voltage Transitions Ramp Time" + * @pre_scaler_to_sysclk_cycles_count: number of entries available + * + * Add parameters that allow us to compute the ramp time for the device + */ +struct setup_time_ramp_params { + u16 *pre_scaler_to_sysclk_cycles; + u8 pre_scaler_to_sysclk_cycles_count; +}; + /** - * struct omap_vc_common_data - per-VC register/bitfield data + * struct omap_vc_common - per-VC register/bitfield data * @cmd_on_mask: ON bitmask in PRM_VC_CMD_VAL* register * @valid: VALID bitmask in PRM_VC_BYPASS_VAL register * @smps_sa_reg: Offset of PRM_VC_SMPS_SA reg from PRM start @@ -33,15 +51,20 @@ * @cmd_onlp_shift: ONLP field shift in PRM_VC_CMD_VAL_* register * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register + * @i2c_cfg_reg: I2C configuration register offset + * @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register + * @i2c_mcode_mask: MCODE field mask for I2C config register + * @setup_time_params: setup time parameters * * XXX One of cmd_on_mask and cmd_on_shift are not needed * XXX VALID should probably be a shift, not a mask */ -struct omap_vc_common_data { +struct omap_vc_common { u32 cmd_on_mask; u32 valid; u8 smps_sa_reg; u8 smps_volra_reg; + u8 smps_cmdra_reg; u8 bypass_val_reg; u8 data_shift; u8 slaveaddr_shift; @@ -50,34 +73,92 @@ struct omap_vc_common_data { u8 cmd_onlp_shift; u8 cmd_ret_shift; u8 cmd_off_shift; + u8 cfg_channel_reg; + u8 i2c_cfg_reg; + u8 i2c_cfg_hsen_mask; + u8 i2c_mcode_mask; + struct setup_time_ramp_params *setup_time_params; +}; + +/** + * struct omap_vc_auto_trans - describe the auto transition for the domain + * @reg: register to modify (usually PRM_VOLTCTRL) + * @sleep_val: value to set for enabling sleep transition + * @retention_val: value to set for enabling retention transition + * @off_val: value to set for enabling off transition + */ +struct omap_vc_auto_trans { + u8 reg; + u8 sleep_val; + u8 retention_val; + u8 off_val; }; +/* omap_vc_channel.flags values */ +#define OMAP_VC_CHANNEL_DEFAULT BIT(0) +#define OMAP_VC_CHANNEL_CFG_MUTANT BIT(1) + /** - * struct omap_vc_instance_data - VC per-instance data - * @vc_common: pointer to VC common data for this platform - * @smps_sa_mask: SA* bitmask in the PRM_VC_SMPS_SA register + * struct omap_vc_channel - VC per-instance data + * @flags: VC channel-specific flags (optional) + * @common: pointer to VC common data for this platform + * @smps_sa_mask: i2c slave address bitmask in the PRM_VC_SMPS_SA register * @smps_volra_mask: VOLRA* bitmask in the PRM_VC_VOL_RA register - * @smps_sa_shift: SA* field shift in the PRM_VC_SMPS_SA register - * @smps_volra_shift: VOLRA* field shift in the PRM_VC_VOL_RA register - * - * XXX It is not necessary to have both a *_mask and a *_shift - - * remove one + * @auto_trans: Auto transition information + * @auto_trans_mask: Auto transition mask for this channel */ -struct omap_vc_instance_data { - const struct omap_vc_common_data *vc_common; +struct omap_vc_channel { + u8 flags; + + /* channel state */ + u16 i2c_slave_addr; + u16 volt_reg_addr; + u16 cmd_reg_addr; + u8 cfg_channel; + u32 setup_time; + u32 setup_voltage_common; + bool i2c_high_speed; + + /* register access data */ + const struct omap_vc_common *common; u32 smps_sa_mask; u32 smps_volra_mask; + u32 smps_cmdra_mask; u8 cmdval_reg; - u8 smps_sa_shift; - u8 smps_volra_shift; + u8 cfg_channel_sa_shift; + + const struct omap_vc_auto_trans *auto_trans; + u32 auto_trans_mask; }; -extern struct omap_vc_instance_data omap3_vc1_data; -extern struct omap_vc_instance_data omap3_vc2_data; +extern struct omap_vc_channel omap3_vc_mpu; +extern struct omap_vc_channel omap3_vc_core; + +extern struct omap_vc_channel omap4_vc_mpu; +extern struct omap_vc_channel omap4_vc_iva; +extern struct omap_vc_channel omap4_vc_core; -extern struct omap_vc_instance_data omap4_vc_mpu_data; -extern struct omap_vc_instance_data omap4_vc_iva_data; -extern struct omap_vc_instance_data omap4_vc_core_data; +void omap_vc_init_channel(struct voltagedomain *voltdm); +int omap_vc_pre_scale(struct voltagedomain *voltdm, + unsigned long target_volt, + struct omap_volt_data *target_vdata, + u8 *target_vsel, u8 *current_vsel); +void omap_vc_post_scale(struct voltagedomain *voltdm, + unsigned long target_volt, + struct omap_volt_data *target_vdata, + u8 target_vsel, u8 current_vsel); +/* Auto transition flags for users */ +#define OMAP_VC_CHANNEL_AUTO_TRANSITION_DISABLE 0 +#define OMAP_VC_CHANNEL_AUTO_TRANSITION_SLEEP 1 +#define OMAP_VC_CHANNEL_AUTO_TRANSITION_RETENTION 2 +#define OMAP_VC_CHANNEL_AUTO_TRANSITION_OFF 3 +/* For silicon data to mark unsupported transition */ +#define OMAP_VC_CHANNEL_AUTO_TRANSITION_UNSUPPORTED 0xff +int omap_vc_set_auto_trans(struct voltagedomain *voltdm, u8 flag); +int omap_vc_bypass_scale_voltage(struct voltagedomain *voltdm, + struct omap_volt_data *target_volt); +int omap_vc_bypass_send_i2c_msg(struct voltagedomain *voltdm, + u8 slave_addr, u8 reg_addr, u8 data); #endif diff --git a/arch/arm/mach-omap2/vc3xxx_data.c b/arch/arm/mach-omap2/vc3xxx_data.c index f37dc4b..c21d3f5 100644 --- a/arch/arm/mach-omap2/vc3xxx_data.c +++ b/arch/arm/mach-omap2/vc3xxx_data.c @@ -29,9 +29,10 @@ * VC data common to 34xx/36xx chips * XXX This stuff presumably belongs in the vc3xxx.c or vc.c file. */ -static struct omap_vc_common_data omap3_vc_common = { +static struct omap_vc_common omap3_vc_common = { .smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET, .smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET, + .smps_cmdra_reg = OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET, .bypass_val_reg = OMAP3_PRM_VC_BYPASS_VAL_OFFSET, .data_shift = OMAP3430_DATA_SHIFT, .slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT, @@ -42,22 +43,42 @@ static struct omap_vc_common_data omap3_vc_common = { .cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT, .cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT, .cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT, + .cfg_channel_reg = OMAP3_PRM_VC_CH_CONF_OFFSET, + .i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK, + .i2c_cfg_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET, + .i2c_mcode_mask = OMAP3430_MCODE_MASK, }; -struct omap_vc_instance_data omap3_vc1_data = { - .vc_common = &omap3_vc_common, +/* + * VC auto transition settings for OMAP3. On OMAP3, we just have a single + * device wide state that is achieved on core, so we shall use this data + * only for core domain transition + */ +static const struct omap_vc_auto_trans omap3_vc_auto_trans = { + .reg = OMAP3_PRM_VOLTCTRL_OFFSET, + .sleep_val = OMAP3430_AUTO_SLEEP_MASK, + .retention_val = OMAP3430_AUTO_RET_MASK, + .off_val = OMAP3430_AUTO_OFF_MASK, +}; + +struct omap_vc_channel omap3_vc_mpu = { + .common = &omap3_vc_common, .cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET, - .smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT, .smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA0_MASK, - .smps_volra_shift = OMAP3430_VOLRA0_SHIFT, .smps_volra_mask = OMAP3430_VOLRA0_MASK, + .smps_cmdra_mask = OMAP3430_CMDRA0_MASK, + .cfg_channel_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT, }; -struct omap_vc_instance_data omap3_vc2_data = { - .vc_common = &omap3_vc_common, +struct omap_vc_channel omap3_vc_core = { + .common = &omap3_vc_common, .cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET, - .smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT, .smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA1_MASK, - .smps_volra_shift = OMAP3430_VOLRA1_SHIFT, .smps_volra_mask = OMAP3430_VOLRA1_MASK, + .smps_cmdra_mask = OMAP3430_CMDRA1_MASK, + .cfg_channel_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT, + + .auto_trans = &omap3_vc_auto_trans, + .auto_trans_mask = OMAP3430_AUTO_OFF_MASK | OMAP3430_AUTO_RET_MASK | + OMAP3430_AUTO_SLEEP_MASK, }; diff --git a/arch/arm/mach-omap2/vc44xx_data.c b/arch/arm/mach-omap2/vc44xx_data.c index a98da8d..08f845b 100644 --- a/arch/arm/mach-omap2/vc44xx_data.c +++ b/arch/arm/mach-omap2/vc44xx_data.c @@ -26,13 +26,20 @@ #include "vc.h" +static u16 pre_scaler_to_sysclk_cycles_44xx[] = {16, 64, 128, 512}; +static struct setup_time_ramp_params omap4_vc_setuptime_params = { + .pre_scaler_to_sysclk_cycles = pre_scaler_to_sysclk_cycles_44xx, + .pre_scaler_to_sysclk_cycles_count = 4, +}; + /* * VC data common to 44xx chips * XXX This stuff presumably belongs in the vc3xxx.c or vc.c file. */ -static const struct omap_vc_common_data omap4_vc_common = { +static const struct omap_vc_common omap4_vc_common = { .smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET, .smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET, + .smps_cmdra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_CMD_OFFSET, .bypass_val_reg = OMAP4_PRM_VC_VAL_BYPASS_OFFSET, .data_shift = OMAP4430_DATA_SHIFT, .slaveaddr_shift = OMAP4430_SLAVEADDR_SHIFT, @@ -43,33 +50,56 @@ static const struct omap_vc_common_data omap4_vc_common = { .cmd_onlp_shift = OMAP4430_ONLP_SHIFT, .cmd_ret_shift = OMAP4430_RET_SHIFT, .cmd_off_shift = OMAP4430_OFF_SHIFT, + .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET, + .i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET, + .i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK, + .i2c_mcode_mask = OMAP4430_HSMCODE_MASK, + .setup_time_params = &omap4_vc_setuptime_params, +}; + +/* VC auto transition settings for OMAP4. */ +static const struct omap_vc_auto_trans omap4_vc_auto_trans = { + .reg = OMAP4_PRM_VOLTCTRL_OFFSET, + .sleep_val = OMAP4430_AUTO_CTRL_VDD_SLEEP_MASK, + .retention_val = OMAP4430_AUTO_CTRL_VDD_RET_MASK, + .off_val = OMAP_VC_CHANNEL_AUTO_TRANSITION_UNSUPPORTED, }; /* VC instance data for each controllable voltage line */ -struct omap_vc_instance_data omap4_vc_mpu_data = { - .vc_common = &omap4_vc_common, +struct omap_vc_channel omap4_vc_mpu = { + .flags = OMAP_VC_CHANNEL_DEFAULT | OMAP_VC_CHANNEL_CFG_MUTANT, + .common = &omap4_vc_common, .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_MPU_L_OFFSET, - .smps_sa_shift = OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_SHIFT, .smps_sa_mask = OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK, - .smps_volra_shift = OMAP4430_VOLRA_VDD_MPU_L_SHIFT, .smps_volra_mask = OMAP4430_VOLRA_VDD_MPU_L_MASK, + .smps_cmdra_mask = OMAP4430_CMDRA_VDD_MPU_L_MASK, + .cfg_channel_sa_shift = OMAP4430_SA_VDD_MPU_L_SHIFT, + + .auto_trans = &omap4_vc_auto_trans, + .auto_trans_mask = OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK, }; -struct omap_vc_instance_data omap4_vc_iva_data = { - .vc_common = &omap4_vc_common, +struct omap_vc_channel omap4_vc_iva = { + .common = &omap4_vc_common, .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_IVA_L_OFFSET, - .smps_sa_shift = OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_SHIFT, .smps_sa_mask = OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK, - .smps_volra_shift = OMAP4430_VOLRA_VDD_IVA_L_SHIFT, .smps_volra_mask = OMAP4430_VOLRA_VDD_IVA_L_MASK, + .smps_cmdra_mask = OMAP4430_CMDRA_VDD_IVA_L_MASK, + .cfg_channel_sa_shift = OMAP4430_SA_VDD_IVA_L_SHIFT, + + .auto_trans = &omap4_vc_auto_trans, + .auto_trans_mask = OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK, }; -struct omap_vc_instance_data omap4_vc_core_data = { - .vc_common = &omap4_vc_common, +struct omap_vc_channel omap4_vc_core = { + .common = &omap4_vc_common, .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_CORE_L_OFFSET, - .smps_sa_shift = OMAP4430_SA_VDD_CORE_L_0_6_SHIFT, .smps_sa_mask = OMAP4430_SA_VDD_CORE_L_0_6_MASK, - .smps_volra_shift = OMAP4430_VOLRA_VDD_CORE_L_SHIFT, .smps_volra_mask = OMAP4430_VOLRA_VDD_CORE_L_MASK, + .smps_cmdra_mask = OMAP4430_CMDRA_VDD_CORE_L_MASK, + .cfg_channel_sa_shift = OMAP4430_SA_VDD_CORE_L_SHIFT, + + .auto_trans = &omap4_vc_auto_trans, + .auto_trans_mask = OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK, }; diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c index 9ef3789..995c38f 100644 --- a/arch/arm/mach-omap2/voltage.c +++ b/arch/arm/mach-omap2/voltage.c @@ -36,633 +36,51 @@ #include "control.h" #include "voltage.h" +#include "powerdomain.h" #include "vc.h" #include "vp.h" -#define VOLTAGE_DIR_SIZE 16 +static LIST_HEAD(voltdm_list); - -static struct omap_vdd_info **vdd_info; - -/* - * Number of scalable voltage domains. - */ -static int nr_scalable_vdd; - -/* XXX document */ -static s16 prm_mod_offs; -static s16 prm_irqst_ocp_mod_offs; - -static struct dentry *voltage_dir; - -/* Init function pointers */ -static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd, - unsigned long target_volt); - -static u32 omap3_voltage_read_reg(u16 mod, u8 offset) +static int __init _config_common_vdd_data(struct voltagedomain *voltdm) { - return omap2_prm_read_mod_reg(mod, offset); -} - -static void omap3_voltage_write_reg(u32 val, u16 mod, u8 offset) -{ - omap2_prm_write_mod_reg(val, mod, offset); -} - -static u32 omap4_voltage_read_reg(u16 mod, u8 offset) -{ - return omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, - mod, offset); -} - -static void omap4_voltage_write_reg(u32 val, u16 mod, u8 offset) -{ - omap4_prminst_write_inst_reg(val, OMAP4430_PRM_PARTITION, mod, offset); -} - -static int __init _config_common_vdd_data(struct omap_vdd_info *vdd) -{ - char *sys_ck_name; struct clk *sys_ck; - u32 sys_clk_speed, timeout_val, waittime; - - /* - * XXX Clockfw should handle this, or this should be in a - * struct record - */ - if (cpu_is_omap24xx() || cpu_is_omap34xx()) - sys_ck_name = "sys_ck"; - else if (cpu_is_omap44xx()) - sys_ck_name = "sys_clkin_ck"; - else - return -EINVAL; /* * Sys clk rate is require to calculate vp timeout value and * smpswaittimemin and smpswaittimemax. */ - sys_ck = clk_get(NULL, sys_ck_name); + sys_ck = clk_get(NULL, voltdm->sys_clk.name); if (IS_ERR(sys_ck)) { pr_warning("%s: Could not get the sys clk to calculate" - "various vdd_%s params\n", __func__, vdd->voltdm.name); + "various vdd_%s params\n", __func__, voltdm->name); return -EINVAL; } - sys_clk_speed = clk_get_rate(sys_ck); - clk_put(sys_ck); - /* Divide to avoid overflow */ - sys_clk_speed /= 1000; + voltdm->sys_clk.rate = clk_get_rate(sys_ck); + WARN_ON(!voltdm->sys_clk.rate); /* Generic voltage parameters */ - vdd->volt_scale = vp_forceupdate_scale_voltage; - vdd->vp_enabled = false; - - vdd->vp_rt_data.vpconfig_erroroffset = - (vdd->pmic_info->vp_erroroffset << - vdd->vp_data->vp_common->vpconfig_erroroffset_shift); - - timeout_val = (sys_clk_speed * vdd->pmic_info->vp_timeout_us) / 1000; - vdd->vp_rt_data.vlimitto_timeout = timeout_val; - vdd->vp_rt_data.vlimitto_vddmin = vdd->pmic_info->vp_vddmin; - vdd->vp_rt_data.vlimitto_vddmax = vdd->pmic_info->vp_vddmax; - - waittime = ((vdd->pmic_info->step_size / vdd->pmic_info->slew_rate) * - sys_clk_speed) / 1000; - vdd->vp_rt_data.vstepmin_smpswaittimemin = waittime; - vdd->vp_rt_data.vstepmax_smpswaittimemax = waittime; - vdd->vp_rt_data.vstepmin_stepmin = vdd->pmic_info->vp_vstepmin; - vdd->vp_rt_data.vstepmax_stepmax = vdd->pmic_info->vp_vstepmax; - - return 0; -} - -/* Voltage debugfs support */ -static int vp_volt_debug_get(void *data, u64 *val) -{ - struct omap_vdd_info *vdd = (struct omap_vdd_info *) data; - u8 vsel; - - if (!vdd) { - pr_warning("Wrong paramater passed\n"); - return -EINVAL; - } - - vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage); - - if (!vdd->pmic_info->vsel_to_uv) { - pr_warning("PMIC function to convert vsel to voltage" - "in uV not registerd\n"); - return -EINVAL; - } - - *val = vdd->pmic_info->vsel_to_uv(vsel); - return 0; -} - -static int nom_volt_debug_get(void *data, u64 *val) -{ - struct omap_vdd_info *vdd = (struct omap_vdd_info *) data; - - if (!vdd) { - pr_warning("Wrong paramater passed\n"); - return -EINVAL; - } - - *val = omap_voltage_get_nom_volt(&vdd->voltdm); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n"); -DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL, - "%llu\n"); -static void vp_latch_vsel(struct omap_vdd_info *vdd) -{ - u32 vpconfig; - unsigned long uvdc; - char vsel; - - uvdc = omap_voltage_get_nom_volt(&vdd->voltdm); - if (!uvdc) { - pr_warning("%s: unable to find current voltage for vdd_%s\n", - __func__, vdd->voltdm.name); - return; - } - - if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) { - pr_warning("%s: PMIC function to convert voltage in uV to" - " vsel not registered\n", __func__); - return; - } - - vsel = vdd->pmic_info->uv_to_vsel(uvdc); - - vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig); - vpconfig &= ~(vdd->vp_data->vp_common->vpconfig_initvoltage_mask | - vdd->vp_data->vp_common->vpconfig_initvdd); - vpconfig |= vsel << vdd->vp_data->vp_common->vpconfig_initvoltage_shift; - - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); - - /* Trigger initVDD value copy to voltage processor */ - vdd->write_reg((vpconfig | vdd->vp_data->vp_common->vpconfig_initvdd), - prm_mod_offs, vdd->vp_data->vpconfig); - - /* Clear initVDD copy trigger bit */ - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); -} - -/* Generic voltage init functions */ -static void __init vp_init(struct omap_vdd_info *vdd) -{ - u32 vp_val; - - if (!vdd->read_reg || !vdd->write_reg) { - pr_err("%s: No read/write API for accessing vdd_%s regs\n", - __func__, vdd->voltdm.name); - return; - } - - vp_val = vdd->vp_rt_data.vpconfig_erroroffset | - (vdd->vp_rt_data.vpconfig_errorgain << - vdd->vp_data->vp_common->vpconfig_errorgain_shift) | - vdd->vp_data->vp_common->vpconfig_timeouten; - vdd->write_reg(vp_val, prm_mod_offs, vdd->vp_data->vpconfig); - - vp_val = ((vdd->vp_rt_data.vstepmin_smpswaittimemin << - vdd->vp_data->vp_common->vstepmin_smpswaittimemin_shift) | - (vdd->vp_rt_data.vstepmin_stepmin << - vdd->vp_data->vp_common->vstepmin_stepmin_shift)); - vdd->write_reg(vp_val, prm_mod_offs, vdd->vp_data->vstepmin); - - vp_val = ((vdd->vp_rt_data.vstepmax_smpswaittimemax << - vdd->vp_data->vp_common->vstepmax_smpswaittimemax_shift) | - (vdd->vp_rt_data.vstepmax_stepmax << - vdd->vp_data->vp_common->vstepmax_stepmax_shift)); - vdd->write_reg(vp_val, prm_mod_offs, vdd->vp_data->vstepmax); - - vp_val = ((vdd->vp_rt_data.vlimitto_vddmax << - vdd->vp_data->vp_common->vlimitto_vddmax_shift) | - (vdd->vp_rt_data.vlimitto_vddmin << - vdd->vp_data->vp_common->vlimitto_vddmin_shift) | - (vdd->vp_rt_data.vlimitto_timeout << - vdd->vp_data->vp_common->vlimitto_timeout_shift)); - vdd->write_reg(vp_val, prm_mod_offs, vdd->vp_data->vlimitto); -} - -static void __init vdd_debugfs_init(struct omap_vdd_info *vdd) -{ - char *name; - - name = kzalloc(VOLTAGE_DIR_SIZE, GFP_KERNEL); - if (!name) { - pr_warning("%s: Unable to allocate memory for debugfs" - " directory name for vdd_%s", - __func__, vdd->voltdm.name); - return; - } - strcpy(name, "vdd_"); - strcat(name, vdd->voltdm.name); - - vdd->debug_dir = debugfs_create_dir(name, voltage_dir); - kfree(name); - if (IS_ERR(vdd->debug_dir)) { - pr_warning("%s: Unable to create debugfs directory for" - " vdd_%s\n", __func__, vdd->voltdm.name); - vdd->debug_dir = NULL; - return; - } - - (void) debugfs_create_x16("vp_errorgain", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vpconfig_errorgain)); - (void) debugfs_create_x16("vp_smpswaittimemin", S_IRUGO, - vdd->debug_dir, - &(vdd->vp_rt_data.vstepmin_smpswaittimemin)); - (void) debugfs_create_x8("vp_stepmin", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vstepmin_stepmin)); - (void) debugfs_create_x16("vp_smpswaittimemax", S_IRUGO, - vdd->debug_dir, - &(vdd->vp_rt_data.vstepmax_smpswaittimemax)); - (void) debugfs_create_x8("vp_stepmax", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vstepmax_stepmax)); - (void) debugfs_create_x8("vp_vddmax", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vlimitto_vddmax)); - (void) debugfs_create_x8("vp_vddmin", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vlimitto_vddmin)); - (void) debugfs_create_x16("vp_timeout", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vlimitto_timeout)); - (void) debugfs_create_file("curr_vp_volt", S_IRUGO, vdd->debug_dir, - (void *) vdd, &vp_volt_debug_fops); - (void) debugfs_create_file("curr_nominal_volt", S_IRUGO, - vdd->debug_dir, (void *) vdd, - &nom_volt_debug_fops); -} - -/* Voltage scale and accessory APIs */ -static int _pre_volt_scale(struct omap_vdd_info *vdd, - unsigned long target_volt, u8 *target_vsel, u8 *current_vsel) -{ - struct omap_volt_data *volt_data; - const struct omap_vc_common_data *vc_common; - const struct omap_vp_common_data *vp_common; - u32 vc_cmdval, vp_errgain_val; - - vc_common = vdd->vc_data->vc_common; - vp_common = vdd->vp_data->vp_common; - - /* Check if suffiecient pmic info is available for this vdd */ - if (!vdd->pmic_info) { - pr_err("%s: Insufficient pmic info to scale the vdd_%s\n", - __func__, vdd->voltdm.name); - return -EINVAL; - } - - if (!vdd->pmic_info->uv_to_vsel) { - pr_err("%s: PMIC function to convert voltage in uV to" - "vsel not registered. Hence unable to scale voltage" - "for vdd_%s\n", __func__, vdd->voltdm.name); - return -ENODATA; - } - - if (!vdd->read_reg || !vdd->write_reg) { - pr_err("%s: No read/write API for accessing vdd_%s regs\n", - __func__, vdd->voltdm.name); - return -EINVAL; - } - - /* Get volt_data corresponding to target_volt */ - volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt); - if (IS_ERR(volt_data)) - volt_data = NULL; - - *target_vsel = vdd->pmic_info->uv_to_vsel(target_volt); - *current_vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage); - - /* Setting the ON voltage to the new target voltage */ - vc_cmdval = vdd->read_reg(prm_mod_offs, vdd->vc_data->cmdval_reg); - vc_cmdval &= ~vc_common->cmd_on_mask; - vc_cmdval |= (*target_vsel << vc_common->cmd_on_shift); - vdd->write_reg(vc_cmdval, prm_mod_offs, vdd->vc_data->cmdval_reg); - - /* Setting vp errorgain based on the voltage */ - if (volt_data) { - vp_errgain_val = vdd->read_reg(prm_mod_offs, - vdd->vp_data->vpconfig); - vdd->vp_rt_data.vpconfig_errorgain = volt_data->vp_errgain; - vp_errgain_val &= ~vp_common->vpconfig_errorgain_mask; - vp_errgain_val |= vdd->vp_rt_data.vpconfig_errorgain << - vp_common->vpconfig_errorgain_shift; - vdd->write_reg(vp_errgain_val, prm_mod_offs, - vdd->vp_data->vpconfig); - } + voltdm->scale = omap_vp_forceupdate_scale; return 0; } -static void _post_volt_scale(struct omap_vdd_info *vdd, - unsigned long target_volt, u8 target_vsel, u8 current_vsel) -{ - u32 smps_steps = 0, smps_delay = 0; - - smps_steps = abs(target_vsel - current_vsel); - /* SMPS slew rate / step size. 2us added as buffer. */ - smps_delay = ((smps_steps * vdd->pmic_info->step_size) / - vdd->pmic_info->slew_rate) + 2; - udelay(smps_delay); - - vdd->curr_volt = target_volt; -} - -/* vc_bypass_scale_voltage - VC bypass method of voltage scaling */ -static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd, - unsigned long target_volt) -{ - u32 loop_cnt = 0, retries_cnt = 0; - u32 vc_valid, vc_bypass_val_reg, vc_bypass_value; - u8 target_vsel, current_vsel; - int ret; - - ret = _pre_volt_scale(vdd, target_volt, &target_vsel, ¤t_vsel); - if (ret) - return ret; - - vc_valid = vdd->vc_data->vc_common->valid; - vc_bypass_val_reg = vdd->vc_data->vc_common->bypass_val_reg; - vc_bypass_value = (target_vsel << vdd->vc_data->vc_common->data_shift) | - (vdd->pmic_info->pmic_reg << - vdd->vc_data->vc_common->regaddr_shift) | - (vdd->pmic_info->i2c_slave_addr << - vdd->vc_data->vc_common->slaveaddr_shift); - - vdd->write_reg(vc_bypass_value, prm_mod_offs, vc_bypass_val_reg); - vdd->write_reg(vc_bypass_value | vc_valid, prm_mod_offs, - vc_bypass_val_reg); - - vc_bypass_value = vdd->read_reg(prm_mod_offs, vc_bypass_val_reg); - /* - * Loop till the bypass command is acknowledged from the SMPS. - * NOTE: This is legacy code. The loop count and retry count needs - * to be revisited. - */ - while (!(vc_bypass_value & vc_valid)) { - loop_cnt++; - - if (retries_cnt > 10) { - pr_warning("%s: Retry count exceeded\n", __func__); - return -ETIMEDOUT; - } - - if (loop_cnt > 50) { - retries_cnt++; - loop_cnt = 0; - udelay(10); - } - vc_bypass_value = vdd->read_reg(prm_mod_offs, - vc_bypass_val_reg); - } - - _post_volt_scale(vdd, target_volt, target_vsel, current_vsel); - return 0; -} - -/* VP force update method of voltage scaling */ -static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd, - unsigned long target_volt) -{ - u32 vpconfig; - u8 target_vsel, current_vsel, prm_irqst_reg; - int ret, timeout = 0; - - ret = _pre_volt_scale(vdd, target_volt, &target_vsel, ¤t_vsel); - if (ret) - return ret; - - prm_irqst_reg = vdd->vp_data->prm_irqst_data->prm_irqst_reg; - - /* - * Clear all pending TransactionDone interrupt/status. Typical latency - * is <3us - */ - while (timeout++ < VP_TRANXDONE_TIMEOUT) { - vdd->write_reg(vdd->vp_data->prm_irqst_data->tranxdone_status, - prm_irqst_ocp_mod_offs, prm_irqst_reg); - if (!(vdd->read_reg(prm_irqst_ocp_mod_offs, prm_irqst_reg) & - vdd->vp_data->prm_irqst_data->tranxdone_status)) - break; - udelay(1); - } - if (timeout >= VP_TRANXDONE_TIMEOUT) { - pr_warning("%s: vdd_%s TRANXDONE timeout exceeded." - "Voltage change aborted", __func__, vdd->voltdm.name); - return -ETIMEDOUT; - } - - /* Configure for VP-Force Update */ - vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig); - vpconfig &= ~(vdd->vp_data->vp_common->vpconfig_initvdd | - vdd->vp_data->vp_common->vpconfig_forceupdate | - vdd->vp_data->vp_common->vpconfig_initvoltage_mask); - vpconfig |= ((target_vsel << - vdd->vp_data->vp_common->vpconfig_initvoltage_shift)); - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); - - /* Trigger initVDD value copy to voltage processor */ - vpconfig |= vdd->vp_data->vp_common->vpconfig_initvdd; - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); - - /* Force update of voltage */ - vpconfig |= vdd->vp_data->vp_common->vpconfig_forceupdate; - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); - - /* - * Wait for TransactionDone. Typical latency is <200us. - * Depends on SMPSWAITTIMEMIN/MAX and voltage change - */ - timeout = 0; - omap_test_timeout((vdd->read_reg(prm_irqst_ocp_mod_offs, prm_irqst_reg) & - vdd->vp_data->prm_irqst_data->tranxdone_status), - VP_TRANXDONE_TIMEOUT, timeout); - if (timeout >= VP_TRANXDONE_TIMEOUT) - pr_err("%s: vdd_%s TRANXDONE timeout exceeded." - "TRANXDONE never got set after the voltage update\n", - __func__, vdd->voltdm.name); - - _post_volt_scale(vdd, target_volt, target_vsel, current_vsel); - - /* - * Disable TransactionDone interrupt , clear all status, clear - * control registers - */ - timeout = 0; - while (timeout++ < VP_TRANXDONE_TIMEOUT) { - vdd->write_reg(vdd->vp_data->prm_irqst_data->tranxdone_status, - prm_irqst_ocp_mod_offs, prm_irqst_reg); - if (!(vdd->read_reg(prm_irqst_ocp_mod_offs, prm_irqst_reg) & - vdd->vp_data->prm_irqst_data->tranxdone_status)) - break; - udelay(1); - } - - if (timeout >= VP_TRANXDONE_TIMEOUT) - pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying" - "to clear the TRANXDONE status\n", - __func__, vdd->voltdm.name); - - vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig); - /* Clear initVDD copy trigger bit */ - vpconfig &= ~vdd->vp_data->vp_common->vpconfig_initvdd; - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); - /* Clear force bit */ - vpconfig &= ~vdd->vp_data->vp_common->vpconfig_forceupdate; - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); - - return 0; -} - -static void __init omap3_vfsm_init(struct omap_vdd_info *vdd) -{ - /* - * Voltage Manager FSM parameters init - * XXX This data should be passed in from the board file - */ - vdd->write_reg(OMAP3_CLKSETUP, prm_mod_offs, OMAP3_PRM_CLKSETUP_OFFSET); - vdd->write_reg(OMAP3_VOLTOFFSET, prm_mod_offs, - OMAP3_PRM_VOLTOFFSET_OFFSET); - vdd->write_reg(OMAP3_VOLTSETUP2, prm_mod_offs, - OMAP3_PRM_VOLTSETUP2_OFFSET); -} - -static void __init omap3_vc_init(struct omap_vdd_info *vdd) -{ - static bool is_initialized; - u8 on_vsel, onlp_vsel, ret_vsel, off_vsel; - u32 vc_val; - - if (is_initialized) - return; - - /* Set up the on, inactive, retention and off voltage */ - on_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->on_volt); - onlp_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->onlp_volt); - ret_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->ret_volt); - off_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->off_volt); - vc_val = ((on_vsel << vdd->vc_data->vc_common->cmd_on_shift) | - (onlp_vsel << vdd->vc_data->vc_common->cmd_onlp_shift) | - (ret_vsel << vdd->vc_data->vc_common->cmd_ret_shift) | - (off_vsel << vdd->vc_data->vc_common->cmd_off_shift)); - vdd->write_reg(vc_val, prm_mod_offs, vdd->vc_data->cmdval_reg); - - /* - * Generic VC parameters init - * XXX This data should be abstracted out - */ - vdd->write_reg(OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK, prm_mod_offs, - OMAP3_PRM_VC_CH_CONF_OFFSET); - vdd->write_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, prm_mod_offs, - OMAP3_PRM_VC_I2C_CFG_OFFSET); - - omap3_vfsm_init(vdd); - - is_initialized = true; -} - - -/* OMAP4 specific voltage init functions */ -static void __init omap4_vc_init(struct omap_vdd_info *vdd) -{ - static bool is_initialized; - u32 vc_val; - - if (is_initialized) - return; - - /* TODO: Configure setup times and CMD_VAL values*/ - - /* - * Generic VC parameters init - * XXX This data should be abstracted out - */ - vc_val = (OMAP4430_RAV_VDD_MPU_L_MASK | OMAP4430_CMD_VDD_MPU_L_MASK | - OMAP4430_RAV_VDD_IVA_L_MASK | OMAP4430_CMD_VDD_IVA_L_MASK | - OMAP4430_RAV_VDD_CORE_L_MASK | OMAP4430_CMD_VDD_CORE_L_MASK); - vdd->write_reg(vc_val, prm_mod_offs, OMAP4_PRM_VC_CFG_CHANNEL_OFFSET); - - /* XXX These are magic numbers and do not belong! */ - vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT); - vdd->write_reg(vc_val, prm_mod_offs, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); - - is_initialized = true; -} - -static void __init omap_vc_init(struct omap_vdd_info *vdd) -{ - u32 vc_val; - - if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) { - pr_err("%s: PMIC info requried to configure vc for" - "vdd_%s not populated.Hence cannot initialize vc\n", - __func__, vdd->voltdm.name); - return; - } - - if (!vdd->read_reg || !vdd->write_reg) { - pr_err("%s: No read/write API for accessing vdd_%s regs\n", - __func__, vdd->voltdm.name); - return; - } - - /* Set up the SMPS_SA(i2c slave address in VC */ - vc_val = vdd->read_reg(prm_mod_offs, - vdd->vc_data->vc_common->smps_sa_reg); - vc_val &= ~vdd->vc_data->smps_sa_mask; - vc_val |= vdd->pmic_info->i2c_slave_addr << vdd->vc_data->smps_sa_shift; - vdd->write_reg(vc_val, prm_mod_offs, - vdd->vc_data->vc_common->smps_sa_reg); - - /* Setup the VOLRA(pmic reg addr) in VC */ - vc_val = vdd->read_reg(prm_mod_offs, - vdd->vc_data->vc_common->smps_volra_reg); - vc_val &= ~vdd->vc_data->smps_volra_mask; - vc_val |= vdd->pmic_info->pmic_reg << vdd->vc_data->smps_volra_shift; - vdd->write_reg(vc_val, prm_mod_offs, - vdd->vc_data->vc_common->smps_volra_reg); - - /* Configure the setup times */ - vc_val = vdd->read_reg(prm_mod_offs, vdd->vfsm->voltsetup_reg); - vc_val &= ~vdd->vfsm->voltsetup_mask; - vc_val |= vdd->pmic_info->volt_setup_time << - vdd->vfsm->voltsetup_shift; - vdd->write_reg(vc_val, prm_mod_offs, vdd->vfsm->voltsetup_reg); - - if (cpu_is_omap34xx()) - omap3_vc_init(vdd); - else if (cpu_is_omap44xx()) - omap4_vc_init(vdd); -} - -static int __init omap_vdd_data_configure(struct omap_vdd_info *vdd) +static int __init omap_vdd_data_configure(struct voltagedomain *voltdm) { int ret = -EINVAL; - if (!vdd->pmic_info) { + if (!voltdm->pmic) { pr_err("%s: PMIC info requried to configure vdd_%s not" "populated.Hence cannot initialize vdd_%s\n", - __func__, vdd->voltdm.name, vdd->voltdm.name); + __func__, voltdm->name, voltdm->name); goto ovdc_out; } - if (IS_ERR_VALUE(_config_common_vdd_data(vdd))) + if (IS_ERR_VALUE(_config_common_vdd_data(voltdm))) goto ovdc_out; - if (cpu_is_omap34xx()) { - vdd->read_reg = omap3_voltage_read_reg; - vdd->write_reg = omap3_voltage_write_reg; - ret = 0; - } else if (cpu_is_omap44xx()) { - vdd->read_reg = omap4_voltage_read_reg; - vdd->write_reg = omap4_voltage_write_reg; - ret = 0; - } + ret = 0; ovdc_out: return ret; @@ -670,205 +88,95 @@ ovdc_out: /* Public functions */ /** - * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage + * omap_voltage_get_curr_vdata() - Gets the current voltage data * @voltdm: pointer to the VDD for which current voltage info is needed * - * API to get the current non-auto-compensated voltage for a VDD. - * Returns 0 in case of error else returns the current voltage for the VDD. - */ -unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm) -{ - struct omap_vdd_info *vdd; - - if (!voltdm || IS_ERR(voltdm)) { - pr_warning("%s: VDD specified does not exist!\n", __func__); - return 0; - } - - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); - - return vdd->curr_volt; -} - -/** - * omap_vp_get_curr_volt() - API to get the current vp voltage. - * @voltdm: pointer to the VDD. - * - * This API returns the current voltage for the specified voltage processor - */ -unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm) -{ - struct omap_vdd_info *vdd; - u8 curr_vsel; - - if (!voltdm || IS_ERR(voltdm)) { - pr_warning("%s: VDD specified does not exist!\n", __func__); - return 0; - } - - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); - if (!vdd->read_reg) { - pr_err("%s: No read API for reading vdd_%s regs\n", - __func__, voltdm->name); - return 0; - } - - curr_vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage); - - if (!vdd->pmic_info || !vdd->pmic_info->vsel_to_uv) { - pr_warning("%s: PMIC function to convert vsel to voltage" - "in uV not registerd\n", __func__); - return 0; - } - - return vdd->pmic_info->vsel_to_uv(curr_vsel); -} - -/** - * omap_vp_enable() - API to enable a particular VP - * @voltdm: pointer to the VDD whose VP is to be enabled. - * - * This API enables a particular voltage processor. Needed by the smartreflex - * class drivers. - */ -void omap_vp_enable(struct voltagedomain *voltdm) -{ - struct omap_vdd_info *vdd; - u32 vpconfig; - - if (!voltdm || IS_ERR(voltdm)) { - pr_warning("%s: VDD specified does not exist!\n", __func__); - return; - } - - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); - if (!vdd->read_reg || !vdd->write_reg) { - pr_err("%s: No read/write API for accessing vdd_%s regs\n", - __func__, voltdm->name); - return; - } - - /* If VP is already enabled, do nothing. Return */ - if (vdd->vp_enabled) - return; - - vp_latch_vsel(vdd); - - /* Enable VP */ - vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig); - vpconfig |= vdd->vp_data->vp_common->vpconfig_vpenable; - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); - vdd->vp_enabled = true; -} - -/** - * omap_vp_disable() - API to disable a particular VP - * @voltdm: pointer to the VDD whose VP is to be disabled. - * - * This API disables a particular voltage processor. Needed by the smartreflex - * class drivers. + * API to get the current voltage data pointer for a VDD, returns NULL on error */ -void omap_vp_disable(struct voltagedomain *voltdm) +struct omap_volt_data *omap_voltage_get_curr_vdata(struct voltagedomain *voltdm) { - struct omap_vdd_info *vdd; - u32 vpconfig; - int timeout; - if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); - return; - } - - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); - if (!vdd->read_reg || !vdd->write_reg) { - pr_err("%s: No read/write API for accessing vdd_%s regs\n", - __func__, voltdm->name); - return; - } - - /* If VP is already disabled, do nothing. Return */ - if (!vdd->vp_enabled) { - pr_warning("%s: Trying to disable VP for vdd_%s when" - "it is already disabled\n", __func__, voltdm->name); - return; + return NULL; } - /* Disable VP */ - vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig); - vpconfig &= ~vdd->vp_data->vp_common->vpconfig_vpenable; - vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig); - - /* - * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us - */ - omap_test_timeout((vdd->read_reg(prm_mod_offs, vdd->vp_data->vstatus)), - VP_IDLE_TIMEOUT, timeout); - - if (timeout >= VP_IDLE_TIMEOUT) - pr_warning("%s: vdd_%s idle timedout\n", - __func__, voltdm->name); - - vdd->vp_enabled = false; - - return; + return voltdm->curr_volt; } /** - * omap_voltage_scale_vdd() - API to scale voltage of a particular - * voltage domain. - * @voltdm: pointer to the VDD which is to be scaled. - * @target_volt: The target voltage of the voltage domain + * voltdm_scale() - API to scale voltage of a particular voltage domain. + * @voltdm: pointer to the voltage domain which is to be scaled. + * @target_volt: The target voltage of the voltage domain * * This API should be called by the kernel to do the voltage scaling - * for a particular voltage domain during dvfs or any other situation. + * for a particular voltage domain during DVFS. */ -int omap_voltage_scale_vdd(struct voltagedomain *voltdm, - unsigned long target_volt) +int voltdm_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_v) { - struct omap_vdd_info *vdd; + int ret = 0; + struct omap_voltage_notifier notify; + unsigned long target_volt = omap_get_operation_voltage(target_v); if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return -EINVAL; } - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); - - if (!vdd->volt_scale) { + if (!voltdm->scale) { pr_err("%s: No voltage scale API registered for vdd_%s\n", __func__, voltdm->name); return -ENODATA; } - return vdd->volt_scale(vdd, target_volt); + notify.voltdm = voltdm; + notify.target_volt = target_volt; + + srcu_notifier_call_chain(&voltdm->change_notify_list, + OMAP_VOLTAGE_PRECHANGE, + (void *)¬ify); + + ret = voltdm->scale(voltdm, target_v); + if (ret) + pr_err("%s: voltage scale failed for vdd%s: %d\n", + __func__, voltdm->name, ret); + + notify.op_result = ret; + srcu_notifier_call_chain(&voltdm->change_notify_list, + OMAP_VOLTAGE_POSTCHANGE, + (void *)¬ify); + + return ret; } /** - * omap_voltage_reset() - Resets the voltage of a particular voltage domain - * to that of the current OPP. - * @voltdm: pointer to the VDD whose voltage is to be reset. + * voltdm_reset() - Resets the voltage of a particular voltage domain + * to that of the current OPP. + * @voltdm: pointer to the voltage domain whose voltage is to be reset. * * This API finds out the correct voltage the voltage domain is supposed * to be at and resets the voltage to that level. Should be used especially * while disabling any voltage compensation modules. + * + * NOTE: appropriate locks should be held for mutual exclusivity. */ -void omap_voltage_reset(struct voltagedomain *voltdm) +void voltdm_reset(struct voltagedomain *voltdm) { - unsigned long target_uvdc; + struct omap_volt_data *target_volt; if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return; } - target_uvdc = omap_voltage_get_nom_volt(voltdm); - if (!target_uvdc) { + target_volt = omap_voltage_get_curr_vdata(voltdm); + if (!target_volt) { pr_err("%s: unable to find current voltage for vdd_%s\n", __func__, voltdm->name); return; } - omap_voltage_scale_vdd(voltdm, target_uvdc); + voltdm_scale(voltdm, target_volt); } /** @@ -893,7 +201,7 @@ void omap_voltage_get_volttable(struct voltagedomain *voltdm, return; } - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); + vdd = voltdm->vdd; *volt_data = vdd->volt_data; } @@ -924,7 +232,7 @@ struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, return ERR_PTR(-EINVAL); } - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); + vdd = voltdm->vdd; if (!vdd->volt_data) { pr_warning("%s: voltage table does not exist for vdd_%s\n", @@ -937,8 +245,8 @@ struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, return &vdd->volt_data[i]; } - pr_notice("%s: Unable to match the current voltage with the voltage" - "table for vdd_%s\n", __func__, voltdm->name); + pr_notice("%s: Unable to match the current voltage %lu with the voltage" + "table for vdd_%s\n", __func__, volt, voltdm->name); return ERR_PTR(-ENODATA); } @@ -947,54 +255,25 @@ struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, * omap_voltage_register_pmic() - API to register PMIC specific data * @voltdm: pointer to the VDD for which the PMIC specific data is * to be registered - * @pmic_info: the structure containing pmic info + * @pmic: the structure containing pmic info * * This API is to be called by the SOC/PMIC file to specify the - * pmic specific info as present in omap_volt_pmic_info structure. + * pmic specific info as present in omap_voltdm_pmic structure. */ int omap_voltage_register_pmic(struct voltagedomain *voltdm, - struct omap_volt_pmic_info *pmic_info) + struct omap_voltdm_pmic *pmic) { - struct omap_vdd_info *vdd; - if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return -EINVAL; } - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); - - vdd->pmic_info = pmic_info; + voltdm->pmic = pmic; return 0; } /** - * omap_voltage_get_dbgdir() - API to get pointer to the debugfs directory - * corresponding to a voltage domain. - * - * @voltdm: pointer to the VDD whose debug directory is required. - * - * This API returns pointer to the debugfs directory corresponding - * to the voltage domain. Should be used by drivers requiring to - * add any debug entry for a particular voltage domain. Returns NULL - * in case of error. - */ -struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm) -{ - struct omap_vdd_info *vdd; - - if (!voltdm || IS_ERR(voltdm)) { - pr_warning("%s: VDD specified does not exist!\n", __func__); - return NULL; - } - - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); - - return vdd->debug_dir; -} - -/** * omap_change_voltscale_method() - API to change the voltage scaling method. * @voltdm: pointer to the VDD whose voltage scaling method * has to be changed. @@ -1005,23 +284,19 @@ struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm) * defined in voltage.h */ void omap_change_voltscale_method(struct voltagedomain *voltdm, - int voltscale_method) + int voltscale_method) { - struct omap_vdd_info *vdd; - if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return; } - vdd = container_of(voltdm, struct omap_vdd_info, voltdm); - switch (voltscale_method) { case VOLTSCALE_VPFORCEUPDATE: - vdd->volt_scale = vp_forceupdate_scale_voltage; + voltdm->scale = omap_vp_forceupdate_scale; return; case VOLTSCALE_VCBYPASS: - vdd->volt_scale = vc_bypass_scale_voltage; + voltdm->scale = omap_vc_bypass_scale_voltage; return; default: pr_warning("%s: Trying to change the method of voltage scaling" @@ -1029,36 +304,147 @@ void omap_change_voltscale_method(struct voltagedomain *voltdm, } } -/** - * omap_voltage_domain_lookup() - API to get the voltage domain pointer - * @name: Name of the voltage domain - * - * This API looks up in the global vdd_info struct for the - * existence of voltage domain <name>. If it exists, the API returns - * a pointer to the voltage domain structure corresponding to the - * VDD<name>. Else retuns error pointer. - */ -struct voltagedomain *omap_voltage_domain_lookup(char *name) +/* Voltage debugfs support */ +static int vp_volt_debug_get(void *data, u64 *val) { - int i; + struct voltagedomain *voltdm = (struct voltagedomain *)data; - if (!vdd_info) { - pr_err("%s: Voltage driver init not yet happened.Faulting!\n", - __func__); - return ERR_PTR(-EINVAL); + if (!voltdm) { + pr_warning("Wrong paramater passed\n"); + return -EINVAL; + } + *val = omap_vp_get_curr_volt(voltdm); + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n"); + +static int dyn_volt_debug_get(void *data, u64 *val) +{ + struct voltagedomain *voltdm = (struct voltagedomain *)data; + struct omap_volt_data *volt_data; + + if (!voltdm) { + pr_warning("%s: Wrong paramater passed\n", __func__); + return -EINVAL; } + volt_data = omap_voltage_get_curr_vdata(voltdm); + if (IS_ERR_OR_NULL(volt_data)) { + pr_warning("%s: No voltage/domain?\n", __func__); + return -ENODEV; + } + + *val = volt_data->volt_dynamic_nominal; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(dyn_volt_debug_fops, dyn_volt_debug_get, NULL, + "%llu\n"); + +static int calib_volt_debug_get(void *data, u64 *val) +{ + struct voltagedomain *voltdm = (struct voltagedomain *)data; + struct omap_volt_data *volt_data; + + if (!voltdm) { + pr_warning("%s: Wrong paramater passed\n", __func__); + return -EINVAL; + } + + volt_data = omap_voltage_get_curr_vdata(voltdm); + if (IS_ERR_OR_NULL(volt_data)) { + pr_warning("%s: No voltage/domain?\n", __func__); + return -ENODEV; + } + + *val = volt_data->volt_calibrated; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(calib_volt_debug_fops, calib_volt_debug_get, NULL, + "%llu\n"); +static int margin_volt_debug_get(void *data, u64 *val) +{ + struct voltagedomain *voltdm = (struct voltagedomain *) data; + struct omap_volt_data *vdata; + + if (!voltdm) { + pr_warning("%s: Wrong parameter passed\n", __func__); + return -EINVAL; + } + + vdata = omap_voltage_get_curr_vdata(voltdm); + if (IS_ERR_OR_NULL(vdata)) { + pr_warning("%s: unable to get volt for vdd_%s\n", + __func__, voltdm->name); + return -ENODEV; + } + *val = vdata->volt_margin; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(margin_volt_debug_fops, margin_volt_debug_get, NULL, + "%llu\n"); + +static int nom_volt_debug_get(void *data, u64 *val) +{ + struct voltagedomain *voltdm = (struct voltagedomain *) data; + struct omap_volt_data *vdata; + + if (!voltdm) { + pr_warning("Wrong paramater passed\n"); + return -EINVAL; + } + + vdata = omap_voltage_get_curr_vdata(voltdm); + if (IS_ERR_OR_NULL(vdata)) { + pr_warning("%s: unable to get volt for vdd_%s\n", + __func__, voltdm->name); + return -ENODEV; + } + *val = vdata->volt_nominal; + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL, + "%llu\n"); + +static void __init voltdm_debugfs_init(struct dentry *voltage_dir, + struct voltagedomain *voltdm) +{ + char *name; + + name = kasprintf(GFP_KERNEL, "vdd_%s", voltdm->name); if (!name) { - pr_err("%s: No name to get the votage domain!\n", __func__); - return ERR_PTR(-EINVAL); + pr_warning("%s:vdd_%s: no mem for debugfs\n", __func__, + voltdm->name); + return; } - for (i = 0; i < nr_scalable_vdd; i++) { - if (!(strcmp(name, vdd_info[i]->voltdm.name))) - return &vdd_info[i]->voltdm; + voltdm->debug_dir = debugfs_create_dir(name, voltage_dir); + kfree(name); + if (IS_ERR_OR_NULL(voltdm->debug_dir)) { + pr_warning("%s: Unable to create debugfs directory for" + " vdd_%s\n", __func__, voltdm->name); + voltdm->debug_dir = NULL; + return; } - return ERR_PTR(-EINVAL); + (void) debugfs_create_file("curr_vp_volt", S_IRUGO, voltdm->debug_dir, + (void *) voltdm, &vp_volt_debug_fops); + (void) debugfs_create_file("curr_nominal_volt", S_IRUGO, + voltdm->debug_dir, (void *) voltdm, + &nom_volt_debug_fops); + (void) debugfs_create_file("curr_dyn_nominal_volt", S_IRUGO, + voltdm->debug_dir, (void *) voltdm, + &dyn_volt_debug_fops); + (void) debugfs_create_file("curr_calibrated_volt", S_IRUGO, + voltdm->debug_dir, (void *) voltdm, + &calib_volt_debug_fops); + (void) debugfs_create_file("curr_margin_volt", S_IRUGO, + voltdm->debug_dir, (void *) voltdm, + &margin_volt_debug_fops); } /** @@ -1070,37 +456,212 @@ struct voltagedomain *omap_voltage_domain_lookup(char *name) */ int __init omap_voltage_late_init(void) { - int i; + struct voltagedomain *voltdm; + struct dentry *voltage_dir; - if (!vdd_info) { + if (list_empty(&voltdm_list)) { pr_err("%s: Voltage driver support not added\n", __func__); return -EINVAL; } voltage_dir = debugfs_create_dir("voltage", NULL); - if (IS_ERR(voltage_dir)) - pr_err("%s: Unable to create voltage debugfs main dir\n", - __func__); - for (i = 0; i < nr_scalable_vdd; i++) { - if (omap_vdd_data_configure(vdd_info[i])) + + list_for_each_entry(voltdm, &voltdm_list, node) { + if (!voltdm->scalable) continue; - omap_vc_init(vdd_info[i]); - vp_init(vdd_info[i]); - vdd_debugfs_init(vdd_info[i]); + + if (voltdm->vdd) { + if (omap_vdd_data_configure(voltdm)) + continue; + omap_vp_init(voltdm); + } + + if (voltdm->vc) + omap_vc_init_channel(voltdm); + + if (voltdm->abb) + omap_ldo_abb_init(voltdm); + + if (voltage_dir) + voltdm_debugfs_init(voltage_dir, voltdm); + + srcu_init_notifier_head(&voltdm->change_notify_list); } return 0; } -/* XXX document */ -int __init omap_voltage_early_init(s16 prm_mod, s16 prm_irqst_ocp_mod, - struct omap_vdd_info *omap_vdd_array[], - u8 omap_vdd_count) +static struct voltagedomain *_voltdm_lookup(const char *name) { - prm_mod_offs = prm_mod; - prm_irqst_ocp_mod_offs = prm_irqst_ocp_mod; - vdd_info = omap_vdd_array; - nr_scalable_vdd = omap_vdd_count; + struct voltagedomain *voltdm, *temp_voltdm; + + voltdm = NULL; + + list_for_each_entry(temp_voltdm, &voltdm_list, node) { + if (!strcmp(name, temp_voltdm->name)) { + voltdm = temp_voltdm; + break; + } + } + + return voltdm; +} + +/** + * omap_voltage_calib_reset() - reset the calibrated voltage entries + * @voltdm: voltage domain to reset the entries for + * + * when the calibrated entries are no longer valid, this api allows + * the calibrated voltages to be reset. + * + * NOTE: Appropriate locks must be held by calling path to ensure mutual + * exclusivity + */ +int omap_voltage_calib_reset(struct voltagedomain *voltdm) +{ + struct omap_volt_data *volt_data; + + if (!voltdm) { + pr_warning("%s: voltdm NULL!\n", __func__); + return -EINVAL; + } + + volt_data = voltdm->vdd->volt_data; + + /* reset the calibrated voltages as 0 */ + while (volt_data->volt_nominal) { + volt_data->volt_calibrated = 0; + volt_data++; + } return 0; } + +/** + * voltdm_add_pwrdm - add a powerdomain to a voltagedomain + * @voltdm: struct voltagedomain * to add the powerdomain to + * @pwrdm: struct powerdomain * to associate with a voltagedomain + * + * Associate the powerdomain @pwrdm with a voltagedomain @voltdm. This + * enables the use of voltdm_for_each_pwrdm(). Returns -EINVAL if + * presented with invalid pointers; -ENOMEM if memory could not be allocated; + * or 0 upon success. + */ +int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm) +{ + if (!voltdm || !pwrdm) + return -EINVAL; + + pr_debug("voltagedomain: associating powerdomain %s with voltagedomain " + "%s\n", pwrdm->name, voltdm->name); + + list_add(&pwrdm->voltdm_node, &voltdm->pwrdm_list); + + return 0; +} + +/** + * voltdm_for_each_pwrdm - call function for each pwrdm in a voltdm + * @voltdm: struct voltagedomain * to iterate over + * @fn: callback function * + * + * Call the supplied function @fn for each powerdomain in the + * voltagedomain @voltdm. Returns -EINVAL if presented with invalid + * pointers; or passes along the last return value of the callback + * function, which should be 0 for success or anything else to + * indicate failure. + */ +int voltdm_for_each_pwrdm(struct voltagedomain *voltdm, + int (*fn)(struct voltagedomain *voltdm, + struct powerdomain *pwrdm)) +{ + struct powerdomain *pwrdm; + int ret = 0; + + if (!fn) + return -EINVAL; + + list_for_each_entry(pwrdm, &voltdm->pwrdm_list, voltdm_node) + ret = (*fn)(voltdm, pwrdm); + + return ret; +} + +/** + * voltdm_for_each - call function on each registered voltagedomain + * @fn: callback function * + * + * Call the supplied function @fn for each registered voltagedomain. + * The callback function @fn can return anything but 0 to bail out + * early from the iterator. Returns the last return value of the + * callback function, which should be 0 for success or anything else + * to indicate failure; or -EINVAL if the function pointer is null. + */ +int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user), + void *user) +{ + struct voltagedomain *temp_voltdm; + int ret = 0; + + if (!fn) + return -EINVAL; + + list_for_each_entry(temp_voltdm, &voltdm_list, node) { + ret = (*fn)(temp_voltdm, user); + if (ret) + break; + } + + return ret; +} + +static int _voltdm_register(struct voltagedomain *voltdm) +{ + if (!voltdm || !voltdm->name) + return -EINVAL; + + INIT_LIST_HEAD(&voltdm->pwrdm_list); + list_add(&voltdm->node, &voltdm_list); + + pr_debug("voltagedomain: registered %s\n", voltdm->name); + + return 0; +} + +/** + * voltdm_lookup - look up a voltagedomain by name, return a pointer + * @name: name of voltagedomain + * + * Find a registered voltagedomain by its name @name. Returns a pointer + * to the struct voltagedomain if found, or NULL otherwise. + */ +struct voltagedomain *voltdm_lookup(const char *name) +{ + struct voltagedomain *voltdm ; + + if (!name) + return NULL; + + voltdm = _voltdm_lookup(name); + + return voltdm; +} + +/** + * voltdm_init - set up the voltagedomain layer + * @voltdm_list: array of struct voltagedomain pointers to register + * + * Loop through the array of voltagedomains @voltdm_list, registering all + * that are available on the current CPU. If voltdm_list is supplied + * and not null, all of the referenced voltagedomains will be + * registered. No return value. + */ +void voltdm_init(struct voltagedomain **voltdms) +{ + struct voltagedomain **v; + + if (voltdms) { + for (v = voltdms; *v; v++) + _voltdm_register(*v); + } +} diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index e9f5408..c454129 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -14,10 +14,16 @@ #ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H #define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H +#include <linux/notifier.h> #include <linux/err.h> +struct omap_volt_data; + #include "vc.h" #include "vp.h" +#include "ldo.h" + +struct powerdomain; /* XXX document */ #define VOLTSCALE_VPFORCEUPDATE 1 @@ -31,35 +37,105 @@ #define OMAP3_VOLTOFFSET 0xff #define OMAP3_VOLTSETUP2 0xff +struct omap_vdd_info; + /** - * struct omap_vfsm_instance_data - per-voltage manager FSM register/bitfield + * struct omap_vfsm_instance - per-voltage manager FSM register/bitfield * data - * @voltsetup_mask: SETUP_TIME* bitmask in the PRM_VOLTSETUP* register - * @voltsetup_reg: register offset of PRM_VOLTSETUP from PRM base + * @voltsetup_mask: SETUP_TIME* bitmask of PRM_VOLTSETUP* register(RET/SLEEP) + * @voltsetup_reg: register offset of PRM_VOLTSETUP from PRM base(RET/SLEEP) * @voltsetup_shift: SETUP_TIME* field shift in the PRM_VOLTSETUP* register + * @voltsetupoff_reg: register offset of PRM_VOLTSETUP*_OFF from PRM base * * XXX What about VOLTOFFSET/VOLTCTRL? * XXX It is not necessary to have both a _mask and a _shift for the same * bitfield - remove one! */ -struct omap_vfsm_instance_data { +struct omap_vfsm_instance { u32 voltsetup_mask; u8 voltsetup_reg; u8 voltsetup_shift; + u8 voltsetupoff_reg; }; +/* Dynamic nominal voltage margin common for OMAP3630 and OMAP4 */ +#define OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV 50000 + /** * struct voltagedomain - omap voltage domain global structure. - * @name: Name of the voltage domain which can be used as a unique - * identifier. + * @name: Name of the voltage domain which can be used as a unique identifier. + * @scalable: Whether or not this voltage domain is scalable + * @node: list_head linking all voltage domains + * @pwrdm_node: list_head linking all powerdomains in this voltagedomain + * @vdd: to be removed + * @pwrdms: powerdomains in this voltagedomain + * @scale: function used to scale the voltage of the voltagedomain + * @curr_volt: current nominal voltage for this voltage domain + * @change_notify_list: notifiers that need to be told on pre and post change */ struct voltagedomain { char *name; + bool scalable; + struct list_head node; + struct list_head pwrdm_list; + struct omap_vc_channel *vc; + const struct omap_vfsm_instance *vfsm; + struct omap_vp_instance *vp; + struct omap_voltdm_pmic *pmic; + struct omap_ldo_abb_instance *abb; + + /* VC/VP register access functions: SoC specific */ + u32 (*read) (u8 offset); + void (*write) (u32 val, u8 offset); + u32 (*rmw)(u32 mask, u32 bits, u8 offset); + + union { + const char *name; + u32 rate; + } sys_clk; + + int (*scale) (struct voltagedomain *voltdm, + struct omap_volt_data *target_volt); + struct omap_volt_data *curr_volt; + + struct omap_vdd_info *vdd; + struct srcu_notifier_head change_notify_list; + struct dentry *debug_dir; +}; + +/* Notifier values for voltage changes */ +#define OMAP_VOLTAGE_PRECHANGE 1 +#define OMAP_VOLTAGE_POSTCHANGE 2 + +/** + * struct omap_voltage_notifier - notifier data that is passed along + * @voltdm: voltage domain for the notification + * @target_volt: what voltage is happening + * @op_result: valid only for POSTCHANGE, tells the result of + * the operation. + * + * This provides notification + */ +struct omap_voltage_notifier { + struct voltagedomain *voltdm; + unsigned long target_volt; + int op_result; }; +/* Flags for various ABB options */ +#define OMAP_ABB_NONE -1 +#define OMAP_ABB_NOMINAL_OPP 0 +#define OMAP_ABB_FAST_OPP 1 + /** * struct omap_volt_data - Omap voltage specific data. * @voltage_nominal: The possible voltage value in uV + * @voltage_calibrated: The Calibrated voltage value in uV + * @voltage_dynamic_nominal: The run time optimized nominal voltage for + * the device. Dynamic nominal is the nominal voltage + * specialized for that OPP on the device in uV. + * @volt_margin: Additional sofware margin in uV to add to OPP calibrated + * voltage * @sr_efuse_offs: The offset of the efuse register(from system * control module base address) from where to read * the n-target value for the smartreflex module. @@ -68,22 +144,69 @@ struct voltagedomain { * with voltage. * @vp_errorgain: Error gain value for the voltage processor. This * field also differs according to the voltage/opp. + * @abb_type: Either OMAP_ABB_NONE - which implies that there is no + * usage of ABB; OMAP_ABB_NOMINAL_OPP - which bypasses ABB + * LDO; or OMAP_ABB_FAST_OPP, which enables Forward-Body + * Bias. */ struct omap_volt_data { u32 volt_nominal; + u32 volt_calibrated; + u32 volt_dynamic_nominal; + u32 volt_margin; u32 sr_efuse_offs; u8 sr_errminlimit; u8 vp_errgain; + int abb_type; }; +/* + * Introduced in OMAP4, is a concept of a default channel - in OMAP4, this + * channel is MPU, all other domains such as IVA/CORE, could optionally + * link their i2c reg configuration to use MPU channel's configuration if + * required. To do this, mark in the PMIC structure's + * i2c_slave_addr, volt_reg_addr,cmd_reg_addr with this macro. + */ +#define USE_DEFAULT_CHANNEL_I2C_PARAM 0x8000 + +/* Min and max voltages from OMAP perspective */ +#define OMAP3430_VP1_VLIMITTO_VDDMIN 850000 +#define OMAP3430_VP1_VLIMITTO_VDDMAX 1425000 +#define OMAP3430_VP2_VLIMITTO_VDDMIN 900000 +#define OMAP3430_VP2_VLIMITTO_VDDMAX 1150000 + +#define OMAP3630_VP1_VLIMITTO_VDDMIN 900000 +#define OMAP3630_VP1_VLIMITTO_VDDMAX 1350000 +#define OMAP3630_VP2_VLIMITTO_VDDMIN 900000 +#define OMAP3630_VP2_VLIMITTO_VDDMAX 1200000 + +#define OMAP4_VP_MPU_VLIMITTO_VDDMIN 830000 +#define OMAP4_VP_MPU_VLIMITTO_VDDMAX 1410000 +#define OMAP4_VP_IVA_VLIMITTO_VDDMIN 830000 +#define OMAP4_VP_IVA_VLIMITTO_VDDMAX 1260000 +#define OMAP4_VP_CORE_VLIMITTO_VDDMIN 830000 +#define OMAP4_VP_CORE_VLIMITTO_VDDMAX 1200000 + +#define OMAP4_VP_CONFIG_ERROROFFSET 0x00 +#define OMAP4_VP_VSTEPMIN_VSTEPMIN 0x01 +#define OMAP4_VP_VSTEPMAX_VSTEPMAX 0x04 +#define OMAP4_VP_VLIMITTO_TIMEOUT_US 200 + /** - * struct omap_volt_pmic_info - PMIC specific data required by voltage driver. + * struct omap_voltdm_pmic - PMIC specific data required by voltage driver. * @slew_rate: PMIC slew rate (in uv/us) * @step_size: PMIC voltage step size (in uv) + * @i2c_high_speed: whether VC uses I2C high-speed mode to PMIC + * @i2c_mcode: master code value for I2C high-speed preamble transmission * @vsel_to_uv: PMIC API to convert vsel value to actual voltage in uV. * @uv_to_vsel: PMIC API to convert voltage in uV to vsel value. + * @i2c_hscll_low: PMIC interface speed config for highspeed mode (T low) + * @i2c_hscll_high: PMIC interface speed config for highspeed mode (T high) + * @i2c_scll_low: PMIC interface speed config for fullspeed mode (T low) + * @i2c_scll_high: PMIC interface speed config for fullspeed mode (T high) + * @switch_on_time: time taken for switch on the DCDC in uSec */ -struct omap_volt_pmic_info { +struct omap_voltdm_pmic { int slew_rate; int step_size; u32 on_volt; @@ -91,81 +214,83 @@ struct omap_volt_pmic_info { u32 ret_volt; u32 off_volt; u16 volt_setup_time; + u16 switch_on_time; u8 vp_erroroffset; u8 vp_vstepmin; u8 vp_vstepmax; - u8 vp_vddmin; - u8 vp_vddmax; + u32 vp_vddmin; + u32 vp_vddmax; u8 vp_timeout_us; - u8 i2c_slave_addr; - u8 pmic_reg; + u16 i2c_slave_addr; + u16 volt_reg_addr; + u16 cmd_reg_addr; + bool i2c_high_speed; + u8 i2c_hscll_low; + u8 i2c_hscll_high; + u8 i2c_scll_low; + u8 i2c_scll_high; + u8 i2c_mcode; unsigned long (*vsel_to_uv) (const u8 vsel); u8 (*uv_to_vsel) (unsigned long uV); }; /** + * struct omap_vdd_dep_volt - Map table for voltage dependencies + * @main_vdd_volt : The main vdd voltage + * @dep_vdd_volt : The voltage at which the dependent vdd should be + * when the main vdd is at <main_vdd_volt> voltage + * + * Table containing the parent vdd voltage and the dependent vdd voltage + * corresponding to it. + */ +struct omap_vdd_dep_volt { + u32 main_vdd_volt; + u32 dep_vdd_volt; +}; + +/** + * struct omap_vdd_dep_info - Dependent vdd info + * @name : Dependent vdd name + * @_dep_voltdm : internal structure meant to prevent multiple lookups + * @dep_table : Table containing the dependent vdd voltage + * corresponding to every main vdd voltage. + * @nr_dep_entries : number of dependency voltage entries + */ +struct omap_vdd_dep_info { + char *name; + struct voltagedomain *_dep_voltdm; + struct omap_vdd_dep_volt *dep_table; + int nr_dep_entries; +}; + +/** * omap_vdd_info - Per Voltage Domain info * - * @volt_data : voltage table having the distinct voltages supported + * @volt_data : Array ending with a 0 terminator containing the + * voltage table with distinct voltages supported * by the domain and other associated per voltage data. - * @pmic_info : pmic specific parameters which should be populted by - * the pmic drivers. - * @vp_data : the register values, shifts, masks for various - * vp registers - * @vp_rt_data : VP data derived at runtime, not predefined - * @vc_data : structure containing various various vc registers, - * shifts, masks etc. - * @vfsm : voltage manager FSM data - * @voltdm : pointer to the voltage domain structure - * @debug_dir : debug directory for this voltage domain. - * @curr_volt : current voltage for this vdd. - * @vp_enabled : flag to keep track of whether vp is enabled or not - * @volt_scale : API to scale the voltage of the vdd. + * @dep_vdd_info : Array ending with a 0 terminator for dependency + * voltage information. */ struct omap_vdd_info { struct omap_volt_data *volt_data; - struct omap_volt_pmic_info *pmic_info; - struct omap_vp_instance_data *vp_data; - struct omap_vp_runtime_data vp_rt_data; - struct omap_vc_instance_data *vc_data; - const struct omap_vfsm_instance_data *vfsm; - struct voltagedomain voltdm; - struct dentry *debug_dir; - u32 curr_volt; - bool vp_enabled; - u32 (*read_reg) (u16 mod, u8 offset); - void (*write_reg) (u32 val, u16 mod, u8 offset); - int (*volt_scale) (struct omap_vdd_info *vdd, - unsigned long target_volt); + struct omap_vdd_dep_info *dep_vdd_info; }; -unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm); -void omap_vp_enable(struct voltagedomain *voltdm); -void omap_vp_disable(struct voltagedomain *voltdm); -int omap_voltage_scale_vdd(struct voltagedomain *voltdm, - unsigned long target_volt); -void omap_voltage_reset(struct voltagedomain *voltdm); void omap_voltage_get_volttable(struct voltagedomain *voltdm, struct omap_volt_data **volt_data); struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, unsigned long volt); -unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm); -struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm); -int __init omap_voltage_early_init(s16 prm_mod, s16 prm_irqst_mod, - struct omap_vdd_info *omap_vdd_array[], - u8 omap_vdd_count); +struct omap_volt_data *omap_voltage_get_curr_vdata(struct voltagedomain *voldm); #ifdef CONFIG_PM int omap_voltage_register_pmic(struct voltagedomain *voltdm, - struct omap_volt_pmic_info *pmic_info); + struct omap_voltdm_pmic *pmic); void omap_change_voltscale_method(struct voltagedomain *voltdm, int voltscale_method); -/* API to get the voltagedomain pointer */ -struct voltagedomain *omap_voltage_domain_lookup(char *name); - int omap_voltage_late_init(void); #else static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm, - struct omap_volt_pmic_info *pmic_info) + struct omap_voltdm_pmic *pmic) { return -EINVAL; } @@ -175,10 +300,69 @@ static inline int omap_voltage_late_init(void) { return -EINVAL; } -static inline struct voltagedomain *omap_voltage_domain_lookup(char *name) +#endif + +extern void omap2xxx_voltagedomains_init(void); +extern void omap3xxx_voltagedomains_init(void); +extern void omap44xx_voltagedomains_init(void); + +struct voltagedomain *voltdm_lookup(const char *name); +void voltdm_init(struct voltagedomain **voltdm_list); +int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm); +int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user), + void *user); +int voltdm_for_each_pwrdm(struct voltagedomain *voltdm, + int (*fn)(struct voltagedomain *voltdm, + struct powerdomain *pwrdm)); +int voltdm_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_volt); +void voltdm_reset(struct voltagedomain *voltdm); + +static inline int voltdm_register_notifier(struct voltagedomain *voltdm, + struct notifier_block *nb) +{ + return srcu_notifier_chain_register(&voltdm->change_notify_list, nb); +} + +static inline int voltdm_unregister_notifier(struct voltagedomain *voltdm, + struct notifier_block *nb) { - return ERR_PTR(-EINVAL); + return srcu_notifier_chain_unregister(&voltdm->change_notify_list, nb); } -#endif + +/* convert volt data to the voltage for the voltage data */ +static inline unsigned long omap_get_operation_voltage( + struct omap_volt_data *vdata) +{ + if (!vdata) + return 0; + return (vdata->volt_calibrated) ? vdata->volt_calibrated : + (vdata->volt_dynamic_nominal) ? vdata->volt_dynamic_nominal : + vdata->volt_nominal; +} + +/* what is my dynamic nominal? */ +static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata) +{ + if (IS_ERR_OR_NULL(vdata)) + return 0; + if (vdata->volt_calibrated) { + unsigned long v = vdata->volt_calibrated + + OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV; + if (v > vdata->volt_nominal) + return vdata->volt_nominal; + return v; + } + return vdata->volt_nominal; +} +static inline unsigned long omap_get_nominal_voltage( + struct omap_volt_data *vdata) +{ + if (IS_ERR_OR_NULL(vdata)) + return 0; + return vdata->volt_nominal; +} + +int omap_voltage_calib_reset(struct voltagedomain *voltdm); #endif diff --git a/arch/arm/mach-omap2/voltagedomains2xxx_data.c b/arch/arm/mach-omap2/voltagedomains2xxx_data.c new file mode 100644 index 0000000..69ff261 --- /dev/null +++ b/arch/arm/mach-omap2/voltagedomains2xxx_data.c @@ -0,0 +1,32 @@ +/* + * OMAP3 voltage domain data + * + * Copyright (C) 2007, 2010 Texas Instruments, Inc. + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/init.h> + +#include "voltage.h" + +static struct voltagedomain omap2_voltdm_core = { + .name = "core", +}; + +static struct voltagedomain omap2_voltdm_wkup = { + .name = "wakeup", +}; + +static struct voltagedomain *voltagedomains_omap2[] __initdata = { + &omap2_voltdm_core, + &omap2_voltdm_wkup, + NULL, +}; + +void __init omap2xxx_voltagedomains_init(void) +{ + voltdm_init(voltagedomains_omap2); +} diff --git a/arch/arm/mach-omap2/voltagedomains3xxx_data.c b/arch/arm/mach-omap2/voltagedomains3xxx_data.c index def230f..65a00ff 100644 --- a/arch/arm/mach-omap2/voltagedomains3xxx_data.c +++ b/arch/arm/mach-omap2/voltagedomains3xxx_data.c @@ -26,55 +26,69 @@ #include "voltage.h" #include "vc.h" #include "vp.h" +#include "ldo.h" /* * VDD data */ -static const struct omap_vfsm_instance_data omap3_vdd1_vfsm_data = { +static const struct omap_vfsm_instance omap3_vdd1_vfsm = { .voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET, .voltsetup_shift = OMAP3430_SETUP_TIME1_SHIFT, .voltsetup_mask = OMAP3430_SETUP_TIME1_MASK, }; -static struct omap_vdd_info omap3_vdd1_info = { - .vp_data = &omap3_vp1_data, - .vc_data = &omap3_vc1_data, - .vfsm = &omap3_vdd1_vfsm_data, - .voltdm = { - .name = "mpu", - }, -}; +static struct omap_vdd_info omap3_vdd1_info; -static const struct omap_vfsm_instance_data omap3_vdd2_vfsm_data = { +static const struct omap_vfsm_instance omap3_vdd2_vfsm = { .voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET, .voltsetup_shift = OMAP3430_SETUP_TIME2_SHIFT, .voltsetup_mask = OMAP3430_SETUP_TIME2_MASK, }; -static struct omap_vdd_info omap3_vdd2_info = { - .vp_data = &omap3_vp2_data, - .vc_data = &omap3_vc2_data, - .vfsm = &omap3_vdd2_vfsm_data, - .voltdm = { - .name = "core", - }, +static struct omap_vdd_info omap3_vdd2_info; + +static struct voltagedomain omap3_voltdm_mpu = { + .name = "mpu_iva", + .scalable = true, + .read = omap3_prm_vcvp_read, + .write = omap3_prm_vcvp_write, + .rmw = omap3_prm_vcvp_rmw, + .vc = &omap3_vc_mpu, + .vfsm = &omap3_vdd1_vfsm, + .vp = &omap3_vp_mpu, + .vdd = &omap3_vdd1_info, }; -/* OMAP3 VDD structures */ -static struct omap_vdd_info *omap3_vdd_info[] = { - &omap3_vdd1_info, - &omap3_vdd2_info, +static struct voltagedomain omap3_voltdm_core = { + .name = "core", + .scalable = true, + .read = omap3_prm_vcvp_read, + .write = omap3_prm_vcvp_write, + .rmw = omap3_prm_vcvp_rmw, + .vc = &omap3_vc_core, + .vfsm = &omap3_vdd2_vfsm, + .vp = &omap3_vp_core, + .vdd = &omap3_vdd2_info, }; -/* OMAP3 specific voltage init functions */ -static int __init omap3xxx_voltage_early_init(void) -{ - s16 prm_mod = OMAP3430_GR_MOD; - s16 prm_irqst_ocp_mod = OCP_MOD; +static struct voltagedomain omap3_voltdm_wkup = { + .name = "wakeup", +}; + +static struct voltagedomain *voltagedomains_omap3[] __initdata = { + &omap3_voltdm_mpu, + &omap3_voltdm_core, + &omap3_voltdm_wkup, + NULL, +}; + +static const char *sys_clk_name __initdata = "sys_ck"; - if (!cpu_is_omap34xx()) - return 0; +void __init omap3xxx_voltagedomains_init(void) +{ + struct voltagedomain *voltdm; + int i; /* * XXX Will depend on the process, validation, and binning @@ -83,13 +97,17 @@ static int __init omap3xxx_voltage_early_init(void) if (cpu_is_omap3630()) { omap3_vdd1_info.volt_data = omap36xx_vddmpu_volt_data; omap3_vdd2_info.volt_data = omap36xx_vddcore_volt_data; + omap3_vdd1_info.dep_vdd_info = omap36xx_vddmpu_dep_info; + omap3_voltdm_mpu.abb = &omap3630_ldo_abb_mpu_instance; + } else { omap3_vdd1_info.volt_data = omap34xx_vddmpu_volt_data; omap3_vdd2_info.volt_data = omap34xx_vddcore_volt_data; + omap3_vdd1_info.dep_vdd_info = omap34xx_vddmpu_dep_info; } - return omap_voltage_early_init(prm_mod, prm_irqst_ocp_mod, - omap3_vdd_info, - ARRAY_SIZE(omap3_vdd_info)); + for (i = 0; voltdm = voltagedomains_omap3[i], voltdm; i++) + voltdm->sys_clk.name = sys_clk_name; + + voltdm_init(voltagedomains_omap3); }; -core_initcall(omap3xxx_voltage_early_init); diff --git a/arch/arm/mach-omap2/voltagedomains44xx_data.c b/arch/arm/mach-omap2/voltagedomains44xx_data.c index cb64996..dc5026e 100644 --- a/arch/arm/mach-omap2/voltagedomains44xx_data.c +++ b/arch/arm/mach-omap2/voltagedomains44xx_data.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/err.h> #include <linux/init.h> +#include <linux/clk.h> #include <plat/common.h> @@ -31,72 +32,135 @@ #include "omap_opp_data.h" #include "vc.h" #include "vp.h" +#include "ldo.h" -static const struct omap_vfsm_instance_data omap4_vdd_mpu_vfsm_data = { +static const struct omap_vfsm_instance omap4_vdd_mpu_vfsm = { .voltsetup_reg = OMAP4_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET, + .voltsetup_mask = OMAP4430_RAMP_DOWN_PRESCAL_MASK | + OMAP4430_RAMP_DOWN_COUNT_MASK | + OMAP4430_RAMP_UP_PRESCAL_MASK | + OMAP4430_RAMP_UP_COUNT_MASK, + .voltsetupoff_reg = OMAP4_PRM_VOLTSETUP_MPU_OFF_OFFSET, }; -static struct omap_vdd_info omap4_vdd_mpu_info = { - .vp_data = &omap4_vp_mpu_data, - .vc_data = &omap4_vc_mpu_data, - .vfsm = &omap4_vdd_mpu_vfsm_data, - .voltdm = { - .name = "mpu", - }, -}; +static struct omap_vdd_info omap4_vdd_mpu_info; -static const struct omap_vfsm_instance_data omap4_vdd_iva_vfsm_data = { +static const struct omap_vfsm_instance omap4_vdd_iva_vfsm = { .voltsetup_reg = OMAP4_PRM_VOLTSETUP_IVA_RET_SLEEP_OFFSET, + .voltsetup_mask = OMAP4430_RAMP_DOWN_PRESCAL_MASK | + OMAP4430_RAMP_DOWN_COUNT_MASK | + OMAP4430_RAMP_UP_PRESCAL_MASK | + OMAP4430_RAMP_UP_COUNT_MASK, + .voltsetupoff_reg = OMAP4_PRM_VOLTSETUP_IVA_OFF_OFFSET, }; -static struct omap_vdd_info omap4_vdd_iva_info = { - .vp_data = &omap4_vp_iva_data, - .vc_data = &omap4_vc_iva_data, - .vfsm = &omap4_vdd_iva_vfsm_data, - .voltdm = { - .name = "iva", - }, -}; +static struct omap_vdd_info omap4_vdd_iva_info; -static const struct omap_vfsm_instance_data omap4_vdd_core_vfsm_data = { +static const struct omap_vfsm_instance omap4_vdd_core_vfsm = { .voltsetup_reg = OMAP4_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET, + .voltsetup_mask = OMAP4430_RAMP_DOWN_PRESCAL_MASK | + OMAP4430_RAMP_DOWN_COUNT_MASK | + OMAP4430_RAMP_UP_PRESCAL_MASK | + OMAP4430_RAMP_UP_COUNT_MASK, + .voltsetupoff_reg = OMAP4_PRM_VOLTSETUP_CORE_OFF_OFFSET, }; -static struct omap_vdd_info omap4_vdd_core_info = { - .vp_data = &omap4_vp_core_data, - .vc_data = &omap4_vc_core_data, - .vfsm = &omap4_vdd_core_vfsm_data, - .voltdm = { - .name = "core", - }, +static struct omap_vdd_info omap4_vdd_core_info; + +static struct voltagedomain omap4_voltdm_mpu = { + .name = "mpu", + .scalable = true, + .read = omap4_prm_vcvp_read, + .write = omap4_prm_vcvp_write, + .rmw = omap4_prm_vcvp_rmw, + .vc = &omap4_vc_mpu, + .vfsm = &omap4_vdd_mpu_vfsm, + .vp = &omap4_vp_mpu, + .vdd = &omap4_vdd_mpu_info, + .abb = &omap4_ldo_abb_mpu_instance, }; -/* OMAP4 VDD structures */ -static struct omap_vdd_info *omap4_vdd_info[] = { - &omap4_vdd_mpu_info, - &omap4_vdd_iva_info, - &omap4_vdd_core_info, +static struct voltagedomain omap4_voltdm_iva = { + .name = "iva", + .scalable = true, + .read = omap4_prm_vcvp_read, + .write = omap4_prm_vcvp_write, + .rmw = omap4_prm_vcvp_rmw, + .vc = &omap4_vc_iva, + .vfsm = &omap4_vdd_iva_vfsm, + .vp = &omap4_vp_iva, + .vdd = &omap4_vdd_iva_info, + .abb = &omap4_ldo_abb_iva_instance, }; -/* OMAP4 specific voltage init functions */ -static int __init omap44xx_voltage_early_init(void) -{ - s16 prm_mod = OMAP4430_PRM_DEVICE_INST; - s16 prm_irqst_ocp_mod = OMAP4430_PRM_OCP_SOCKET_INST; +static struct voltagedomain omap4_voltdm_core = { + .name = "core", + .scalable = true, + .read = omap4_prm_vcvp_read, + .write = omap4_prm_vcvp_write, + .rmw = omap4_prm_vcvp_rmw, + .vc = &omap4_vc_core, + .vfsm = &omap4_vdd_core_vfsm, + .vp = &omap4_vp_core, + .vdd = &omap4_vdd_core_info, +}; + +static struct voltagedomain omap4_voltdm_wkup = { + .name = "wakeup", +}; + +static struct voltagedomain *voltagedomains_omap4[] __initdata = { + &omap4_voltdm_mpu, + &omap4_voltdm_iva, + &omap4_voltdm_core, + &omap4_voltdm_wkup, + NULL, +}; + +/* + * Handle Mutant pre_scalar to sysclk cycles map: + * Due to "Errata Id: i623: Retention/Sleep Voltage Transitions Ramp Time" + * on OMAP4430 specifically, the maps is 64, 256, 512, 2048 cycles. + * Handle this condition dynamically from version detection logic + */ +static u16 pre_scaler_to_sysclk_cycles_443x[] = {64, 256, 512, 2048}; - if (!cpu_is_omap44xx()) - return 0; +static const char *sys_clk_name __initdata = "sys_clkin_ck"; + +void __init omap44xx_voltagedomains_init(void) +{ + struct voltagedomain *voltdm; + int i; /* * XXX Will depend on the process, validation, and binning * for the currently-running IC */ - omap4_vdd_mpu_info.volt_data = omap44xx_vdd_mpu_volt_data; - omap4_vdd_iva_info.volt_data = omap44xx_vdd_iva_volt_data; - omap4_vdd_core_info.volt_data = omap44xx_vdd_core_volt_data; + if (cpu_is_omap443x()) { + struct setup_time_ramp_params *params = + omap4_vc_core.common->setup_time_params; + + if (params) { + params->pre_scaler_to_sysclk_cycles = + pre_scaler_to_sysclk_cycles_443x; + } + omap4_vdd_mpu_info.volt_data = omap443x_vdd_mpu_volt_data; + omap4_vdd_iva_info.volt_data = omap443x_vdd_iva_volt_data; + omap4_vdd_core_info.volt_data = omap443x_vdd_core_volt_data; + omap4_vdd_mpu_info.dep_vdd_info = omap443x_vddmpu_dep_info; + omap4_vdd_iva_info.dep_vdd_info = omap443x_vddiva_dep_info; + } else if (cpu_is_omap446x()) { + omap4_vdd_mpu_info.volt_data = omap446x_vdd_mpu_volt_data; + omap4_vdd_iva_info.volt_data = omap446x_vdd_iva_volt_data; + omap4_vdd_core_info.volt_data = omap446x_vdd_core_volt_data; + omap4_vdd_mpu_info.dep_vdd_info = omap446x_vddmpu_dep_info; + omap4_vdd_iva_info.dep_vdd_info = omap446x_vddiva_dep_info; + } else { + return; + } + + for (i = 0; voltdm = voltagedomains_omap4[i], voltdm; i++) + voltdm->sys_clk.name = sys_clk_name; - return omap_voltage_early_init(prm_mod, prm_irqst_ocp_mod, - omap4_vdd_info, - ARRAY_SIZE(omap4_vdd_info)); + voltdm_init(voltagedomains_omap4); }; -core_initcall(omap44xx_voltage_early_init); diff --git a/arch/arm/mach-omap2/vp.c b/arch/arm/mach-omap2/vp.c new file mode 100644 index 0000000..3f16be5 --- /dev/null +++ b/arch/arm/mach-omap2/vp.c @@ -0,0 +1,426 @@ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/ratelimit.h> + +#include <plat/common.h> + +#include "voltage.h" +#include "vp.h" +#include "prm-regbits-34xx.h" +#include "prm-regbits-44xx.h" +#include "prm44xx.h" + +static void vp_latch_vsel(struct voltagedomain *voltdm) +{ + struct omap_vp_instance *vp = voltdm->vp; + struct omap_volt_data *v = omap_voltage_get_curr_vdata(voltdm); + u32 vpconfig; + unsigned long uvdc; + char vsel; + + if (IS_ERR_OR_NULL(v)) { + pr_warning("%s: unable to get voltage for vdd_%s\n", + __func__, voltdm->name); + return; + } + uvdc = omap_get_operation_voltage(v); + if (!uvdc) { + pr_warning("%s: unable to find current voltage for vdd_%s\n", + __func__, voltdm->name); + return; + } + + if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) { + pr_warning("%s: PMIC function to convert voltage in uV to" + " vsel not registered\n", __func__); + return; + } + + vsel = voltdm->pmic->uv_to_vsel(uvdc); + + vpconfig = voltdm->read(vp->vpconfig); + vpconfig &= ~(vp->common->vpconfig_initvoltage_mask | + vp->common->vpconfig_initvdd); + vpconfig |= vsel << __ffs(vp->common->vpconfig_initvoltage_mask); + voltdm->write(vpconfig, vp->vpconfig); + + /* Trigger initVDD value copy to voltage processor */ + voltdm->write((vpconfig | vp->common->vpconfig_initvdd), + vp->vpconfig); + + /* Clear initVDD copy trigger bit */ + voltdm->write(vpconfig, vp->vpconfig); +} + +/* Generic voltage init functions */ +void __init omap_vp_init(struct voltagedomain *voltdm) +{ + struct omap_vp_instance *vp = voltdm->vp; + u32 val, sys_clk_rate, timeout, waittime; + u32 vddmin, vddmax, vstepmin, vstepmax; + + if (!voltdm->read || !voltdm->write) { + pr_err("%s: No read/write API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + vp->enabled = false; + + /* Divide to avoid overflow */ + sys_clk_rate = voltdm->sys_clk.rate / 1000; + + timeout = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000; + vddmin = voltdm->pmic->uv_to_vsel(voltdm->pmic->vp_vddmin); + vddmax = voltdm->pmic->uv_to_vsel(voltdm->pmic->vp_vddmax); + + waittime = DIV_ROUND_UP(voltdm->pmic->step_size * sys_clk_rate, + 1000 * voltdm->pmic->slew_rate); + vstepmin = voltdm->pmic->vp_vstepmin; + vstepmax = voltdm->pmic->vp_vstepmax; + + /* + * VP_CONFIG: error gain is not set here, it will be updated + * on each scale, based on OPP. + */ + val = (voltdm->pmic->vp_erroroffset << + __ffs(voltdm->vp->common->vpconfig_erroroffset_mask)) | + vp->common->vpconfig_timeouten; + voltdm->write(val, vp->vpconfig); + + /* VSTEPMIN */ + val = (waittime << vp->common->vstepmin_smpswaittimemin_shift) | + (vstepmin << vp->common->vstepmin_stepmin_shift); + voltdm->write(val, vp->vstepmin); + + /* VSTEPMAX */ + val = (vstepmax << vp->common->vstepmax_stepmax_shift) | + (waittime << vp->common->vstepmax_smpswaittimemax_shift); + voltdm->write(val, vp->vstepmax); + + /* VLIMITTO */ + val = (vddmax << vp->common->vlimitto_vddmax_shift) | + (vddmin << vp->common->vlimitto_vddmin_shift) | + (timeout << vp->common->vlimitto_timeout_shift); + voltdm->write(val, vp->vlimitto); +} + +/** + * omap_vp_is_transdone() - is voltage transfer done on vp? + * @voltdm: pointer to the VDD which is to be scaled. + * + * VP's transdone bit is the only way to ensure that the transfer + * of the voltage value has actually been send over to the PMIC + * This is hence useful for all users of voltage domain to precisely + * identify once the PMIC voltage has been set by the voltage processor + */ +bool omap_vp_is_transdone(struct voltagedomain *voltdm) +{ + + struct omap_vp_instance *vp = voltdm->vp; + + return vp->common->ops->check_txdone(vp->id) ? true : false; +} + +/** + * omap_vp_clear_transdone() - clear voltage transfer done status on vp + * @voltdm: pointer to the VDD which is to be scaled. + */ +void omap_vp_clear_transdone(struct voltagedomain *voltdm) +{ + struct omap_vp_instance *vp = voltdm->vp; + + vp->common->ops->clear_txdone(vp->id); + + return; +} + +int omap_vp_update_errorgain(struct voltagedomain *voltdm, + struct omap_volt_data *volt_data) +{ + if (IS_ERR_OR_NULL(volt_data)) { + pr_err("%s: vdm %s bad voltage data %p\n", __func__, + voltdm->name, volt_data); + return -EINVAL; + } + + /* Setting vp errorgain based on the voltage */ + voltdm->rmw(voltdm->vp->common->vpconfig_errorgain_mask, + volt_data->vp_errgain << + __ffs(voltdm->vp->common->vpconfig_errorgain_mask), + voltdm->vp->vpconfig); + + return 0; +} + +#define _MAX_RETRIES_BEFORE_RECOVER 50 +#define _MAX_COUNT_ERR 10 +static u8 __vp_debug_error_message_count = _MAX_COUNT_ERR; +static u8 __vp_recover_count = _MAX_RETRIES_BEFORE_RECOVER; +/* Dump with stack the first few messages, tone down severity for the rest */ +#define _vp_controlled_err(vp, voltdm, ARGS...) \ +{ \ + if (__vp_debug_error_message_count) { \ + pr_err(ARGS); \ + dump_stack(); \ + __vp_debug_error_message_count--; \ + } else { \ + pr_err_ratelimited(ARGS); \ + } \ + if ((vp)->common->ops->recover && !(--__vp_recover_count)) { \ + pr_err("%s:domain %s recovery count triggered\n", \ + __func__, (voltdm)->name); \ + (vp)->common->ops->recover((vp)->id); \ + __vp_recover_count =_MAX_RETRIES_BEFORE_RECOVER; \ + } \ +} + + +/* VP force update method of voltage scaling */ +int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_v) +{ + struct omap_vp_instance *vp = voltdm->vp; + u32 vpconfig; + u8 target_vsel, current_vsel; + int ret, timeout = 0; + unsigned long target_volt = omap_get_operation_voltage(target_v); + + /* + * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us + * This is an additional allowance to ensure we are in proper state + * to enter into forceupdate state transition. + */ + omap_test_timeout((voltdm->read(vp->vstatus) & vp->common->vstatus_vpidle), + VP_IDLE_TIMEOUT, timeout); + + if (timeout >= VP_IDLE_TIMEOUT) + _vp_controlled_err(vp, voltdm, + "%s:vdd_%s idletimdout forceupdate(v=%ld)\n", + __func__, voltdm->name, target_volt); + + ret = omap_vc_pre_scale(voltdm, target_volt, target_v, + &target_vsel, ¤t_vsel); + if (ret) + return ret; + + /* + * Clear all pending TransactionDone interrupt/status. Typical latency + * is <3us + */ + while (timeout++ < VP_TRANXDONE_TIMEOUT) { + vp->common->ops->clear_txdone(vp->id); + if (!vp->common->ops->check_txdone(vp->id)) + break; + udelay(1); + } + if (timeout >= VP_TRANXDONE_TIMEOUT) { + _vp_controlled_err(vp, voltdm, + "%s: vdd_%s TRANXDONE timeout exceeded." + "Voltage change aborted target volt=%ld," + "target vsel=0x%02x, current_vsel=0x%02x\n", + __func__, voltdm->name, target_volt, + target_vsel, current_vsel); + return -ETIMEDOUT; + } + + /* Configure for VP-Force Update */ + vpconfig = voltdm->read(vp->vpconfig); + vpconfig &= ~(vp->common->vpconfig_initvdd | + vp->common->vpconfig_forceupdate | + vp->common->vpconfig_initvoltage_mask); + vpconfig |= ((target_vsel << + __ffs(vp->common->vpconfig_initvoltage_mask))); + voltdm->write(vpconfig, vp->vpconfig); + + /* Trigger initVDD value copy to voltage processor */ + vpconfig |= vp->common->vpconfig_initvdd; + voltdm->write(vpconfig, vp->vpconfig); + + /* Force update of voltage */ + vpconfig |= vp->common->vpconfig_forceupdate; + voltdm->write(vpconfig, vp->vpconfig); + + /* + * Wait for TransactionDone. Typical latency is <200us. + * Depends on SMPSWAITTIMEMIN/MAX and voltage change + */ + timeout = 0; + omap_test_timeout(vp->common->ops->check_txdone(vp->id), + VP_TRANXDONE_TIMEOUT, timeout); + if (timeout >= VP_TRANXDONE_TIMEOUT) + _vp_controlled_err(vp, voltdm, + "%s: vdd_%s TRANXDONE timeout exceeded. " + "TRANXDONE never got set after the voltage update. " + "target volt=%ld, target vsel=0x%02x, " + "current_vsel=0x%02x\n", + __func__, voltdm->name, target_volt, + target_vsel, current_vsel); + + omap_vc_post_scale(voltdm, target_volt, target_v, + target_vsel, current_vsel); + + /* + * Disable TransactionDone interrupt , clear all status, clear + * control registers + */ + timeout = 0; + while (timeout++ < VP_TRANXDONE_TIMEOUT) { + vp->common->ops->clear_txdone(vp->id); + if (!vp->common->ops->check_txdone(vp->id)) + break; + udelay(1); + } + + if (timeout >= VP_TRANXDONE_TIMEOUT) + _vp_controlled_err(vp, voltdm, + "%s: vdd_%s TRANXDONE timeout exceeded while" + "trying to clear the TRANXDONE status. target volt=%ld," + "target vsel=0x%02x, current_vsel=0x%02x\n", + __func__, voltdm->name, target_volt, + target_vsel, current_vsel); + + vpconfig = voltdm->read(vp->vpconfig); + /* Clear initVDD copy trigger bit */ + vpconfig &= ~vp->common->vpconfig_initvdd; + voltdm->write(vpconfig, vp->vpconfig); + /* Clear force bit */ + vpconfig &= ~vp->common->vpconfig_forceupdate; + voltdm->write(vpconfig, vp->vpconfig); + + return 0; +} + +/** + * omap_vp_get_curr_volt() - API to get the current vp voltage. + * @voltdm: pointer to the VDD. + * + * This API returns the current voltage for the specified voltage processor + */ +unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm) +{ + struct omap_vp_instance *vp = voltdm->vp; + u8 curr_vsel; + + if (!voltdm || IS_ERR(voltdm)) { + pr_warning("%s: VDD specified does not exist!\n", __func__); + return 0; + } + + if (!voltdm->read) { + pr_err("%s: No read API for reading vdd_%s regs\n", + __func__, voltdm->name); + return 0; + } + + curr_vsel = (voltdm->read(vp->voltage) & vp->common->vpvoltage_mask) + >> __ffs(vp->common->vpvoltage_mask); + + if (!voltdm->pmic || !voltdm->pmic->vsel_to_uv) { + pr_warning("%s: PMIC function to convert vsel to voltage" + "in uV not registerd\n", __func__); + return 0; + } + + return voltdm->pmic->vsel_to_uv(curr_vsel); +} + +/** + * omap_vp_enable() - API to enable a particular VP + * @voltdm: pointer to the VDD whose VP is to be enabled. + * + * This API enables a particular voltage processor. Needed by the smartreflex + * class drivers. + */ +void omap_vp_enable(struct voltagedomain *voltdm) +{ + struct omap_vp_instance *vp; + u32 vpconfig; + + if (!voltdm || IS_ERR(voltdm)) { + pr_warning("%s: VDD specified does not exist!\n", __func__); + return; + } + + vp = voltdm->vp; + if (!voltdm->read || !voltdm->write) { + pr_err("%s: No read/write API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + /* If VP is already enabled, do nothing. Return */ + if (vp->enabled) + return; + + vp_latch_vsel(voltdm); + + /* Enable VP */ + vpconfig = voltdm->read(vp->vpconfig); + vpconfig |= vp->common->vpconfig_vpenable; + voltdm->write(vpconfig, vp->vpconfig); + vp->enabled = true; +} + +/** + * omap_vp_disable() - API to disable a particular VP + * @voltdm: pointer to the VDD whose VP is to be disabled. + * + * This API disables a particular voltage processor. Needed by the smartreflex + * class drivers. + */ +void omap_vp_disable(struct voltagedomain *voltdm) +{ + struct omap_vp_instance *vp; + u32 vpconfig; + int timeout; + + if (!voltdm || IS_ERR(voltdm)) { + pr_warning("%s: VDD specified does not exist!\n", __func__); + return; + } + + vp = voltdm->vp; + if (!voltdm->read || !voltdm->write) { + pr_err("%s: No read/write API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + /* If VP is already disabled, do nothing. Return */ + if (!vp->enabled) { + pr_warning("%s: Trying to disable VP for vdd_%s when" + "it is already disabled\n", __func__, voltdm->name); + return; + } + + /* + * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us + * Depending on if we catch VP in the middle of an SR operation. + */ + omap_test_timeout((voltdm->read(vp->vstatus) & vp->common->vstatus_vpidle), + VP_IDLE_TIMEOUT, timeout); + + if (timeout >= VP_IDLE_TIMEOUT) + pr_warning("%s: vdd_%s idle timedout before disable\n", + __func__, voltdm->name); + + /* Disable VP */ + vpconfig = voltdm->read(vp->vpconfig); + vpconfig &= ~vp->common->vpconfig_vpenable; + voltdm->write(vpconfig, vp->vpconfig); + + /* + * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us + */ + omap_test_timeout((voltdm->read(vp->vstatus) & vp->common->vstatus_vpidle), + VP_IDLE_TIMEOUT, timeout); + + if (timeout >= VP_IDLE_TIMEOUT) + pr_warning("%s: vdd_%s idle timedout after disable\n", + __func__, voltdm->name); + + vp->enabled = false; + + return; +} diff --git a/arch/arm/mach-omap2/vp.h b/arch/arm/mach-omap2/vp.h index 7ce134f..cb3465a 100644 --- a/arch/arm/mach-omap2/vp.h +++ b/arch/arm/mach-omap2/vp.h @@ -19,44 +19,53 @@ #include <linux/kernel.h> +struct voltagedomain; + /* XXX document */ -#define VP_IDLE_TIMEOUT 200 +#define VP_IDLE_TIMEOUT 500 #define VP_TRANXDONE_TIMEOUT 300 +/** + * struct omap_vp_ops - per-VP operations + * @check_txdone: check for VP transaction done + * @clear_txdone: clear VP transaction done status + */ +struct omap_vp_ops { + u32 (*check_txdone)(u8 vp_id); + void (*clear_txdone)(u8 vp_id); + void (*recover)(u8 vp_id); +}; /** - * struct omap_vp_common_data - register data common to all VDDs + * struct omap_vp_common - register data common to all VDDs + * @vpconfig_erroroffset_mask: ERROROFFSET bitmask in the PRM_VP*_CONFIG reg * @vpconfig_errorgain_mask: ERRORGAIN bitmask in the PRM_VP*_CONFIG reg * @vpconfig_initvoltage_mask: INITVOLTAGE bitmask in the PRM_VP*_CONFIG reg - * @vpconfig_timeouten_mask: TIMEOUT bitmask in the PRM_VP*_CONFIG reg + * @vpconfig_timeouten: TIMEOUT bitmask in the PRM_VP*_CONFIG reg * @vpconfig_initvdd: INITVDD bitmask in the PRM_VP*_CONFIG reg * @vpconfig_forceupdate: FORCEUPDATE bitmask in the PRM_VP*_CONFIG reg * @vpconfig_vpenable: VPENABLE bitmask in the PRM_VP*_CONFIG reg * @vpconfig_erroroffset_shift: ERROROFFSET field shift in PRM_VP*_CONFIG reg * @vpconfig_errorgain_shift: ERRORGAIN field shift in PRM_VP*_CONFIG reg * @vpconfig_initvoltage_shift: INITVOLTAGE field shift in PRM_VP*_CONFIG reg - * @vpconfig_stepmin_shift: VSTEPMIN field shift in the PRM_VP*_VSTEPMIN reg - * @vpconfig_smpswaittimemin_shift: SMPSWAITTIMEMIN field shift in PRM_VP*_VSTEPMIN reg - * @vpconfig_stepmax_shift: VSTEPMAX field shift in the PRM_VP*_VSTEPMAX reg - * @vpconfig_smpswaittimemax_shift: SMPSWAITTIMEMAX field shift in PRM_VP*_VSTEPMAX reg - * @vpconfig_vlimitto_vddmin_shift: VDDMIN field shift in PRM_VP*_VLIMITTO reg - * @vpconfig_vlimitto_vddmax_shift: VDDMAX field shift in PRM_VP*_VLIMITTO reg - * @vpconfig_vlimitto_timeout_shift: TIMEOUT field shift in PRM_VP*_VLIMITTO reg - * - * XXX It it not necessary to have both a mask and a shift for the same - * bitfield - remove one - * XXX Many of these fields are wrongly named -- e.g., vpconfig_smps* -- fix! + * @vstepmin_stepmin_shift: VSTEPMIN field shift in the PRM_VP*_VSTEPMIN reg + * @vstepmin_smpswaittimemin_shift: SMPSWAITTIMEMIN field shift in PRM_VP*_VSTEPMIN reg + * @vstepmax_stepmax_shift: VSTEPMAX field shift in the PRM_VP*_VSTEPMAX reg + * @vstepmax_smpswaittimemax_shift: SMPSWAITTIMEMAX field shift in PRM_VP*_VSTEPMAX reg + * @vlimitto_vddmin_shift: VDDMIN field shift in PRM_VP*_VLIMITTO reg + * @vlimitto_vddmax_shift: VDDMAX field shift in PRM_VP*_VLIMITTO reg + * @vlimitto_timeout_shift: TIMEOUT field shift in PRM_VP*_VLIMITTO reg + * @vpvoltage_mask: VPVOLTAGE field mask in PRM_VP*_VOLTAGE reg */ -struct omap_vp_common_data { +struct omap_vp_common { + u32 vpconfig_erroroffset_mask; u32 vpconfig_errorgain_mask; u32 vpconfig_initvoltage_mask; - u32 vpconfig_timeouten; - u32 vpconfig_initvdd; - u32 vpconfig_forceupdate; - u32 vpconfig_vpenable; - u8 vpconfig_erroroffset_shift; - u8 vpconfig_errorgain_shift; - u8 vpconfig_initvoltage_shift; + u8 vpconfig_timeouten; + u8 vpconfig_initvdd; + u8 vpconfig_forceupdate; + u8 vpconfig_vpenable; + u8 vstatus_vpidle; u8 vstepmin_stepmin_shift; u8 vstepmin_smpswaittimemin_shift; u8 vstepmax_stepmax_shift; @@ -64,80 +73,51 @@ struct omap_vp_common_data { u8 vlimitto_vddmin_shift; u8 vlimitto_vddmax_shift; u8 vlimitto_timeout_shift; -}; + u8 vpvoltage_mask; -/** - * struct omap_vp_prm_irqst_data - PRM_IRQSTATUS_MPU.VP_TRANXDONE_ST data - * @prm_irqst_reg: reg offset for PRM_IRQSTATUS_MPU from top of PRM - * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg - * - * XXX prm_irqst_reg does not belong here - * XXX Note that on OMAP3, VP_TRANXDONE interrupt may not work due to a - * hardware bug - * XXX This structure is probably not needed - */ -struct omap_vp_prm_irqst_data { - u8 prm_irqst_reg; - u32 tranxdone_status; + const struct omap_vp_ops *ops; }; /** - * struct omap_vp_instance_data - VP register offsets (per-VDD) - * @vp_common: pointer to struct omap_vp_common_data * for this SoC - * @prm_irqst_data: pointer to struct omap_vp_prm_irqst_data for this VDD + * struct omap_vp_instance - VP register offsets (per-VDD) + * @common: pointer to struct omap_vp_common * for this SoC * @vpconfig: PRM_VP*_CONFIG reg offset from PRM start * @vstepmin: PRM_VP*_VSTEPMIN reg offset from PRM start * @vlimitto: PRM_VP*_VLIMITTO reg offset from PRM start * @vstatus: PRM_VP*_VSTATUS reg offset from PRM start * @voltage: PRM_VP*_VOLTAGE reg offset from PRM start + * @enabled: flag to keep track of whether vp is enabled or not * * XXX vp_common is probably not needed since it is per-SoC */ -struct omap_vp_instance_data { - const struct omap_vp_common_data *vp_common; - const struct omap_vp_prm_irqst_data *prm_irqst_data; +struct omap_vp_instance { + const struct omap_vp_common *common; u8 vpconfig; u8 vstepmin; u8 vstepmax; u8 vlimitto; u8 vstatus; u8 voltage; + u8 id; + bool enabled; }; -/** - * struct omap_vp_runtime_data - VP data populated at runtime by code - * @vpconfig_erroroffset: value of ERROROFFSET bitfield in PRM_VP*_CONFIG - * @vpconfig_errorgain: value of ERRORGAIN bitfield in PRM_VP*_CONFIG - * @vstepmin_smpswaittimemin: value of SMPSWAITTIMEMIN bitfield in PRM_VP*_VSTEPMIN - * @vstepmax_smpswaittimemax: value of SMPSWAITTIMEMAX bitfield in PRM_VP*_VSTEPMAX - * @vlimitto_timeout: value of TIMEOUT bitfield in PRM_VP*_VLIMITTO - * @vstepmin_stepmin: value of VSTEPMIN bitfield in PRM_VP*_VSTEPMIN - * @vstepmax_stepmax: value of VSTEPMAX bitfield in PRM_VP*_VSTEPMAX - * @vlimitto_vddmin: value of VDDMIN bitfield in PRM_VP*_VLIMITTO - * @vlimitto_vddmax: value of VDDMAX bitfield in PRM_VP*_VLIMITTO - * - * XXX Is this structure really needed? Why not just program the - * device directly? They are in PRM space, therefore in the WKUP - * powerdomain, so register contents should not be lost in off-mode. - * XXX Some of these fields are incorrectly named, e.g., vstep* - */ -struct omap_vp_runtime_data { - u32 vpconfig_erroroffset; - u16 vpconfig_errorgain; - u16 vstepmin_smpswaittimemin; - u16 vstepmax_smpswaittimemax; - u16 vlimitto_timeout; - u8 vstepmin_stepmin; - u8 vstepmax_stepmax; - u8 vlimitto_vddmin; - u8 vlimitto_vddmax; -}; +extern struct omap_vp_instance omap3_vp_mpu; +extern struct omap_vp_instance omap3_vp_core; -extern struct omap_vp_instance_data omap3_vp1_data; -extern struct omap_vp_instance_data omap3_vp2_data; +extern struct omap_vp_instance omap4_vp_mpu; +extern struct omap_vp_instance omap4_vp_iva; +extern struct omap_vp_instance omap4_vp_core; -extern struct omap_vp_instance_data omap4_vp_mpu_data; -extern struct omap_vp_instance_data omap4_vp_iva_data; -extern struct omap_vp_instance_data omap4_vp_core_data; +void omap_vp_init(struct voltagedomain *voltdm); +void omap_vp_enable(struct voltagedomain *voltdm); +void omap_vp_disable(struct voltagedomain *voltdm); +unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm); +int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, + struct omap_volt_data *target_v); +int omap_vp_update_errorgain(struct voltagedomain *voltdm, + struct omap_volt_data *volt_data); +bool omap_vp_is_transdone(struct voltagedomain *voltdm); +void omap_vp_clear_transdone(struct voltagedomain *voltdm); #endif diff --git a/arch/arm/mach-omap2/vp3xxx_data.c b/arch/arm/mach-omap2/vp3xxx_data.c index 6452170..6db2604 100644 --- a/arch/arm/mach-omap2/vp3xxx_data.c +++ b/arch/arm/mach-omap2/vp3xxx_data.c @@ -25,21 +25,26 @@ #include "voltage.h" #include "vp.h" +#include "prm2xxx_3xxx.h" + +static const struct omap_vp_ops omap3_vp_ops = { + .check_txdone = omap3_prm_vp_check_txdone, + .clear_txdone = omap3_prm_vp_clear_txdone, +}; /* * VP data common to 34xx/36xx chips * XXX This stuff presumably belongs in the vp3xxx.c or vp.c file. */ -static const struct omap_vp_common_data omap3_vp_common = { - .vpconfig_erroroffset_shift = OMAP3430_ERROROFFSET_SHIFT, +static const struct omap_vp_common omap3_vp_common = { + .vpconfig_erroroffset_mask = OMAP3430_ERROROFFSET_MASK, .vpconfig_errorgain_mask = OMAP3430_ERRORGAIN_MASK, - .vpconfig_errorgain_shift = OMAP3430_ERRORGAIN_SHIFT, - .vpconfig_initvoltage_shift = OMAP3430_INITVOLTAGE_SHIFT, .vpconfig_initvoltage_mask = OMAP3430_INITVOLTAGE_MASK, .vpconfig_timeouten = OMAP3430_TIMEOUTEN_MASK, .vpconfig_initvdd = OMAP3430_INITVDD_MASK, .vpconfig_forceupdate = OMAP3430_FORCEUPDATE_MASK, .vpconfig_vpenable = OMAP3430_VPENABLE_MASK, + .vstatus_vpidle = OMAP3430_VPINIDLE_MASK, .vstepmin_smpswaittimemin_shift = OMAP3430_SMPSWAITTIMEMIN_SHIFT, .vstepmax_smpswaittimemax_shift = OMAP3430_SMPSWAITTIMEMAX_SHIFT, .vstepmin_stepmin_shift = OMAP3430_VSTEPMIN_SHIFT, @@ -47,36 +52,29 @@ static const struct omap_vp_common_data omap3_vp_common = { .vlimitto_vddmin_shift = OMAP3430_VDDMIN_SHIFT, .vlimitto_vddmax_shift = OMAP3430_VDDMAX_SHIFT, .vlimitto_timeout_shift = OMAP3430_TIMEOUT_SHIFT, -}; + .vpvoltage_mask = OMAP3430_VPVOLTAGE_MASK, -static const struct omap_vp_prm_irqst_data omap3_vp1_prm_irqst_data = { - .prm_irqst_reg = OMAP3_PRM_IRQSTATUS_MPU_OFFSET, - .tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK, + .ops = &omap3_vp_ops, }; -struct omap_vp_instance_data omap3_vp1_data = { - .vp_common = &omap3_vp_common, +struct omap_vp_instance omap3_vp_mpu = { + .id = OMAP3_PRM_IRQ_VDD_MPU_ID, + .common = &omap3_vp_common, .vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET, .vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET, .vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET, .vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET, .vstatus = OMAP3_PRM_VP1_STATUS_OFFSET, .voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET, - .prm_irqst_data = &omap3_vp1_prm_irqst_data, -}; - -static const struct omap_vp_prm_irqst_data omap3_vp2_prm_irqst_data = { - .prm_irqst_reg = OMAP3_PRM_IRQSTATUS_MPU_OFFSET, - .tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK, }; -struct omap_vp_instance_data omap3_vp2_data = { - .vp_common = &omap3_vp_common, +struct omap_vp_instance omap3_vp_core = { + .id = OMAP3_PRM_IRQ_VDD_CORE_ID, + .common = &omap3_vp_common, .vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET, .vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET, .vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET, .vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET, .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET, .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET, - .prm_irqst_data = &omap3_vp2_prm_irqst_data, }; diff --git a/arch/arm/mach-omap2/vp44xx_data.c b/arch/arm/mach-omap2/vp44xx_data.c index 65d1ad6..da6fed9 100644 --- a/arch/arm/mach-omap2/vp44xx_data.c +++ b/arch/arm/mach-omap2/vp44xx_data.c @@ -21,26 +21,38 @@ #include <plat/common.h> +#include "pm.h" #include "prm44xx.h" #include "prm-regbits-44xx.h" #include "voltage.h" #include "vp.h" +/* OMAP4 is hooked such that only a cold reset will reset VP */ +static void omap4_vp_recover(u8 vp_id) +{ + omap4_pm_cold_reset("Voltage Processor Recovery"); +} + +static const struct omap_vp_ops omap4_vp_ops = { + .check_txdone = omap4_prm_vp_check_txdone, + .clear_txdone = omap4_prm_vp_clear_txdone, + .recover = omap4_vp_recover, +}; + /* * VP data common to 44xx chips * XXX This stuff presumably belongs in the vp44xx.c or vp.c file. */ -static const struct omap_vp_common_data omap4_vp_common = { - .vpconfig_erroroffset_shift = OMAP4430_ERROROFFSET_SHIFT, +static const struct omap_vp_common omap4_vp_common = { + .vpconfig_erroroffset_mask = OMAP4430_ERROROFFSET_MASK, .vpconfig_errorgain_mask = OMAP4430_ERRORGAIN_MASK, - .vpconfig_errorgain_shift = OMAP4430_ERRORGAIN_SHIFT, - .vpconfig_initvoltage_shift = OMAP4430_INITVOLTAGE_SHIFT, .vpconfig_initvoltage_mask = OMAP4430_INITVOLTAGE_MASK, .vpconfig_timeouten = OMAP4430_TIMEOUTEN_MASK, .vpconfig_initvdd = OMAP4430_INITVDD_MASK, .vpconfig_forceupdate = OMAP4430_FORCEUPDATE_MASK, .vpconfig_vpenable = OMAP4430_VPENABLE_MASK, + .vstatus_vpidle = OMAP4430_VPINIDLE_MASK, .vstepmin_smpswaittimemin_shift = OMAP4430_SMPSWAITTIMEMIN_SHIFT, .vstepmax_smpswaittimemax_shift = OMAP4430_SMPSWAITTIMEMAX_SHIFT, .vstepmin_stepmin_shift = OMAP4430_VSTEPMIN_SHIFT, @@ -48,53 +60,39 @@ static const struct omap_vp_common_data omap4_vp_common = { .vlimitto_vddmin_shift = OMAP4430_VDDMIN_SHIFT, .vlimitto_vddmax_shift = OMAP4430_VDDMAX_SHIFT, .vlimitto_timeout_shift = OMAP4430_TIMEOUT_SHIFT, + .vpvoltage_mask = OMAP4430_VPVOLTAGE_MASK, + .ops = &omap4_vp_ops, }; -static const struct omap_vp_prm_irqst_data omap4_vp_mpu_prm_irqst_data = { - .prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET, - .tranxdone_status = OMAP4430_VP_MPU_TRANXDONE_ST_MASK, -}; - -struct omap_vp_instance_data omap4_vp_mpu_data = { - .vp_common = &omap4_vp_common, +struct omap_vp_instance omap4_vp_mpu = { + .id = OMAP4_PRM_IRQ_VDD_MPU_ID, + .common = &omap4_vp_common, .vpconfig = OMAP4_PRM_VP_MPU_CONFIG_OFFSET, .vstepmin = OMAP4_PRM_VP_MPU_VSTEPMIN_OFFSET, .vstepmax = OMAP4_PRM_VP_MPU_VSTEPMAX_OFFSET, .vlimitto = OMAP4_PRM_VP_MPU_VLIMITTO_OFFSET, .vstatus = OMAP4_PRM_VP_MPU_STATUS_OFFSET, .voltage = OMAP4_PRM_VP_MPU_VOLTAGE_OFFSET, - .prm_irqst_data = &omap4_vp_mpu_prm_irqst_data, }; -static const struct omap_vp_prm_irqst_data omap4_vp_iva_prm_irqst_data = { - .prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_OFFSET, - .tranxdone_status = OMAP4430_VP_IVA_TRANXDONE_ST_MASK, -}; - -struct omap_vp_instance_data omap4_vp_iva_data = { - .vp_common = &omap4_vp_common, +struct omap_vp_instance omap4_vp_iva = { + .id = OMAP4_PRM_IRQ_VDD_IVA_ID, + .common = &omap4_vp_common, .vpconfig = OMAP4_PRM_VP_IVA_CONFIG_OFFSET, .vstepmin = OMAP4_PRM_VP_IVA_VSTEPMIN_OFFSET, .vstepmax = OMAP4_PRM_VP_IVA_VSTEPMAX_OFFSET, .vlimitto = OMAP4_PRM_VP_IVA_VLIMITTO_OFFSET, .vstatus = OMAP4_PRM_VP_IVA_STATUS_OFFSET, .voltage = OMAP4_PRM_VP_IVA_VOLTAGE_OFFSET, - .prm_irqst_data = &omap4_vp_iva_prm_irqst_data, }; -static const struct omap_vp_prm_irqst_data omap4_vp_core_prm_irqst_data = { - .prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_OFFSET, - .tranxdone_status = OMAP4430_VP_CORE_TRANXDONE_ST_MASK, -}; - -struct omap_vp_instance_data omap4_vp_core_data = { - .vp_common = &omap4_vp_common, +struct omap_vp_instance omap4_vp_core = { + .id = OMAP4_PRM_IRQ_VDD_CORE_ID, + .common = &omap4_vp_common, .vpconfig = OMAP4_PRM_VP_CORE_CONFIG_OFFSET, .vstepmin = OMAP4_PRM_VP_CORE_VSTEPMIN_OFFSET, .vstepmax = OMAP4_PRM_VP_CORE_VSTEPMAX_OFFSET, .vlimitto = OMAP4_PRM_VP_CORE_VLIMITTO_OFFSET, .vstatus = OMAP4_PRM_VP_CORE_STATUS_OFFSET, .voltage = OMAP4_PRM_VP_CORE_VOLTAGE_OFFSET, - .prm_irqst_data = &omap4_vp_core_prm_irqst_data, }; - |