diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/bus/mvebu-mbus.c | 277 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 1 | ||||
-rw-r--r-- | drivers/clocksource/Kconfig | 3 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 2 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra.c | 1 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra30.c | 9 | ||||
-rw-r--r-- | drivers/soc/tegra/pmc.c | 124 |
7 files changed, 350 insertions, 67 deletions
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index eb7682dc123b..fb9ec6221730 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -58,6 +58,7 @@ #include <linux/debugfs.h> #include <linux/log2.h> #include <linux/syscore_ops.h> +#include <linux/memblock.h> /* * DDR target is the same on all platforms. @@ -69,6 +70,7 @@ */ #define WIN_CTRL_OFF 0x0000 #define WIN_CTRL_ENABLE BIT(0) +#define WIN_CTRL_SYNCBARRIER BIT(1) #define WIN_CTRL_TGT_MASK 0xf0 #define WIN_CTRL_TGT_SHIFT 4 #define WIN_CTRL_ATTR_MASK 0xff00 @@ -82,6 +84,9 @@ #define WIN_REMAP_LOW 0xffff0000 #define WIN_REMAP_HI_OFF 0x000c +#define UNIT_SYNC_BARRIER_OFF 0x84 +#define UNIT_SYNC_BARRIER_ALL 0xFFFF + #define ATTR_HW_COHERENCY (0x1 << 4) #define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) @@ -97,7 +102,9 @@ /* Relative to mbusbridge_base */ #define MBUS_BRIDGE_CTRL_OFF 0x0 +#define MBUS_BRIDGE_SIZE_MASK 0xffff0000 #define MBUS_BRIDGE_BASE_OFF 0x4 +#define MBUS_BRIDGE_BASE_MASK 0xffff0000 /* Maximum number of windows, for all known platforms */ #define MBUS_WINS_MAX 20 @@ -106,9 +113,9 @@ struct mvebu_mbus_state; struct mvebu_mbus_soc_data { unsigned int num_wins; - unsigned int num_remappable_wins; bool has_mbus_bridge; unsigned int (*win_cfg_offset)(const int win); + unsigned int (*win_remap_offset)(const int win); void (*setup_cpu_target)(struct mvebu_mbus_state *s); int (*save_cpu_target)(struct mvebu_mbus_state *s, u32 *store_addr); @@ -154,6 +161,13 @@ const struct mbus_dram_target_info *mv_mbus_dram_info(void) } EXPORT_SYMBOL_GPL(mv_mbus_dram_info); +/* Checks whether the given window has remap capability */ +static bool mvebu_mbus_window_is_remappable(struct mvebu_mbus_state *mbus, + const int win) +{ + return mbus->soc->win_remap_offset(win) != MVEBU_MBUS_NO_REMAP; +} + /* * Functions to manipulate the address decoding windows */ @@ -185,9 +199,12 @@ static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus, *attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT; if (remap) { - if (win < mbus->soc->num_remappable_wins) { - u32 remap_low = readl(addr + WIN_REMAP_LO_OFF); - u32 remap_hi = readl(addr + WIN_REMAP_HI_OFF); + if (mvebu_mbus_window_is_remappable(mbus, win)) { + u32 remap_low, remap_hi; + void __iomem *addr_rmp = mbus->mbuswins_base + + mbus->soc->win_remap_offset(win); + remap_low = readl(addr_rmp + WIN_REMAP_LO_OFF); + remap_hi = readl(addr_rmp + WIN_REMAP_HI_OFF); *remap = ((u64)remap_hi << 32) | remap_low; } else *remap = 0; @@ -200,22 +217,25 @@ static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus, void __iomem *addr; addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win); - writel(0, addr + WIN_BASE_OFF); writel(0, addr + WIN_CTRL_OFF); - if (win < mbus->soc->num_remappable_wins) { + + if (mvebu_mbus_window_is_remappable(mbus, win)) { + addr = mbus->mbuswins_base + mbus->soc->win_remap_offset(win); writel(0, addr + WIN_REMAP_LO_OFF); writel(0, addr + WIN_REMAP_HI_OFF); } } /* Checks whether the given window number is available */ + static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus, const int win) { void __iomem *addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win); u32 ctrl = readl(addr + WIN_CTRL_OFF); + return !(ctrl & WIN_CTRL_ENABLE); } @@ -303,17 +323,22 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus, ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) | (attr << WIN_CTRL_ATTR_SHIFT) | (target << WIN_CTRL_TGT_SHIFT) | + WIN_CTRL_SYNCBARRIER | WIN_CTRL_ENABLE; writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF); writel(ctrl, addr + WIN_CTRL_OFF); - if (win < mbus->soc->num_remappable_wins) { + + if (mvebu_mbus_window_is_remappable(mbus, win)) { + void __iomem *addr_rmp = mbus->mbuswins_base + + mbus->soc->win_remap_offset(win); + if (remap == MVEBU_MBUS_NO_REMAP) remap_addr = base; else remap_addr = remap; - writel(remap_addr & WIN_REMAP_LOW, addr + WIN_REMAP_LO_OFF); - writel(0, addr + WIN_REMAP_HI_OFF); + writel(remap_addr & WIN_REMAP_LOW, addr_rmp + WIN_REMAP_LO_OFF); + writel(0, addr_rmp + WIN_REMAP_HI_OFF); } return 0; @@ -327,19 +352,27 @@ static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus, int win; if (remap == MVEBU_MBUS_NO_REMAP) { - for (win = mbus->soc->num_remappable_wins; - win < mbus->soc->num_wins; win++) + for (win = 0; win < mbus->soc->num_wins; win++) { + if (mvebu_mbus_window_is_remappable(mbus, win)) + continue; + if (mvebu_mbus_window_is_free(mbus, win)) return mvebu_mbus_setup_window(mbus, win, base, size, remap, target, attr); + } } + for (win = 0; win < mbus->soc->num_wins; win++) { + /* Skip window if need remap but is not supported */ + if ((remap != MVEBU_MBUS_NO_REMAP) && + !mvebu_mbus_window_is_remappable(mbus, win)) + continue; - for (win = 0; win < mbus->soc->num_wins; win++) if (mvebu_mbus_window_is_free(mbus, win)) return mvebu_mbus_setup_window(mbus, win, base, size, remap, target, attr); + } return -ENOMEM; } @@ -451,7 +484,7 @@ static int mvebu_devs_debug_show(struct seq_file *seq, void *v) ((wbase & (u64)(wsize - 1)) != 0)) seq_puts(seq, " (Invalid base/size!!)"); - if (win < mbus->soc->num_remappable_wins) { + if (mvebu_mbus_window_is_remappable(mbus, win)) { seq_printf(seq, " (remap %016llx)\n", (unsigned long long)wremap); } else @@ -477,12 +510,12 @@ static const struct file_operations mvebu_devs_debug_fops = { * SoC-specific functions and definitions */ -static unsigned int orion_mbus_win_offset(int win) +static unsigned int generic_mbus_win_cfg_offset(int win) { return win << 4; } -static unsigned int armada_370_xp_mbus_win_offset(int win) +static unsigned int armada_370_xp_mbus_win_cfg_offset(int win) { /* The register layout is a bit annoying and the below code * tries to cope with it. @@ -502,7 +535,7 @@ static unsigned int armada_370_xp_mbus_win_offset(int win) return 0x90 + ((win - 8) << 3); } -static unsigned int mv78xx0_mbus_win_offset(int win) +static unsigned int mv78xx0_mbus_win_cfg_offset(int win) { if (win < 8) return win << 4; @@ -510,36 +543,140 @@ static unsigned int mv78xx0_mbus_win_offset(int win) return 0x900 + ((win - 8) << 4); } +static unsigned int generic_mbus_win_remap_2_offset(int win) +{ + if (win < 2) + return generic_mbus_win_cfg_offset(win); + else + return MVEBU_MBUS_NO_REMAP; +} + +static unsigned int generic_mbus_win_remap_4_offset(int win) +{ + if (win < 4) + return generic_mbus_win_cfg_offset(win); + else + return MVEBU_MBUS_NO_REMAP; +} + +static unsigned int generic_mbus_win_remap_8_offset(int win) +{ + if (win < 8) + return generic_mbus_win_cfg_offset(win); + else + return MVEBU_MBUS_NO_REMAP; +} + +static unsigned int armada_xp_mbus_win_remap_offset(int win) +{ + if (win < 8) + return generic_mbus_win_cfg_offset(win); + else if (win == 13) + return 0xF0 - WIN_REMAP_LO_OFF; + else + return MVEBU_MBUS_NO_REMAP; +} + +/* + * Use the memblock information to find the MBus bridge hole in the + * physical address space. + */ +static void __init +mvebu_mbus_find_bridge_hole(uint64_t *start, uint64_t *end) +{ + struct memblock_region *r; + uint64_t s = 0; + + for_each_memblock(memory, r) { + /* + * This part of the memory is above 4 GB, so we don't + * care for the MBus bridge hole. + */ + if (r->base >= 0x100000000) + continue; + + /* + * The MBus bridge hole is at the end of the RAM under + * the 4 GB limit. + */ + if (r->base + r->size > s) + s = r->base + r->size; + } + + *start = s; + *end = 0x100000000; +} + static void __init mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) { int i; int cs; + uint64_t mbus_bridge_base, mbus_bridge_end; mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR; + mvebu_mbus_find_bridge_hole(&mbus_bridge_base, &mbus_bridge_end); + for (i = 0, cs = 0; i < 4; i++) { - u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i)); - u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i)); + u64 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i)); + u64 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i)); + u64 end; + struct mbus_dram_window *w; + + /* Ignore entries that are not enabled */ + if (!(size & DDR_SIZE_ENABLED)) + continue; /* - * We only take care of entries for which the chip - * select is enabled, and that don't have high base - * address bits set (devices can only access the first - * 32 bits of the memory). + * Ignore entries whose base address is above 2^32, + * since devices cannot DMA to such high addresses */ - if ((size & DDR_SIZE_ENABLED) && - !(base & DDR_BASE_CS_HIGH_MASK)) { - struct mbus_dram_window *w; + if (base & DDR_BASE_CS_HIGH_MASK) + continue; - w = &mvebu_mbus_dram_info.cs[cs++]; - w->cs_index = i; - w->mbus_attr = 0xf & ~(1 << i); - if (mbus->hw_io_coherency) - w->mbus_attr |= ATTR_HW_COHERENCY; - w->base = base & DDR_BASE_CS_LOW_MASK; - w->size = (size | ~DDR_SIZE_MASK) + 1; + base = base & DDR_BASE_CS_LOW_MASK; + size = (size | ~DDR_SIZE_MASK) + 1; + end = base + size; + + /* + * Adjust base/size of the current CS to make sure it + * doesn't overlap with the MBus bridge hole. This is + * particularly important for devices that do DMA from + * DRAM to a SRAM mapped in a MBus window, such as the + * CESA cryptographic engine. + */ + + /* + * The CS is fully enclosed inside the MBus bridge + * area, so ignore it. + */ + if (base >= mbus_bridge_base && end <= mbus_bridge_end) + continue; + + /* + * Beginning of CS overlaps with end of MBus, raise CS + * base address, and shrink its size. + */ + if (base >= mbus_bridge_base && end > mbus_bridge_end) { + size -= mbus_bridge_end - base; + base = mbus_bridge_end; } + + /* + * End of CS overlaps with beginning of MBus, shrink + * CS size. + */ + if (base < mbus_bridge_base && end > mbus_bridge_base) + size -= end - mbus_bridge_base; + + w = &mvebu_mbus_dram_info.cs[cs++]; + w->cs_index = i; + w->mbus_attr = 0xf & ~(1 << i); + if (mbus->hw_io_coherency) + w->mbus_attr |= ATTR_HW_COHERENCY; + w->base = base; + w->size = size; } mvebu_mbus_dram_info.num_cs = cs; } @@ -619,30 +756,40 @@ int mvebu_mbus_save_cpu_target(u32 *store_addr) return mbus_state.soc->save_cpu_target(&mbus_state, store_addr); } -static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { +static const struct mvebu_mbus_soc_data armada_370_mbus_data = { .num_wins = 20, - .num_remappable_wins = 8, .has_mbus_bridge = true, - .win_cfg_offset = armada_370_xp_mbus_win_offset, + .win_cfg_offset = armada_370_xp_mbus_win_cfg_offset, + .win_remap_offset = generic_mbus_win_remap_8_offset, + .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, + .show_cpu_target = mvebu_sdram_debug_show_orion, .save_cpu_target = mvebu_mbus_default_save_cpu_target, +}; + +static const struct mvebu_mbus_soc_data armada_xp_mbus_data = { + .num_wins = 20, + .has_mbus_bridge = true, + .win_cfg_offset = armada_370_xp_mbus_win_cfg_offset, + .win_remap_offset = armada_xp_mbus_win_remap_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, + .save_cpu_target = mvebu_mbus_default_save_cpu_target, }; static const struct mvebu_mbus_soc_data kirkwood_mbus_data = { .num_wins = 8, - .num_remappable_wins = 4, - .win_cfg_offset = orion_mbus_win_offset, + .win_cfg_offset = generic_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_default_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_4_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; static const struct mvebu_mbus_soc_data dove_mbus_data = { .num_wins = 8, - .num_remappable_wins = 4, - .win_cfg_offset = orion_mbus_win_offset, + .win_cfg_offset = generic_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_dove_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_4_offset, .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_dove, }; @@ -653,36 +800,40 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = { */ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = { .num_wins = 8, - .num_remappable_wins = 4, - .win_cfg_offset = orion_mbus_win_offset, + .win_cfg_offset = generic_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_default_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_4_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = { .num_wins = 8, - .num_remappable_wins = 2, - .win_cfg_offset = orion_mbus_win_offset, + .win_cfg_offset = generic_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_default_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_2_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = { .num_wins = 14, - .num_remappable_wins = 8, - .win_cfg_offset = mv78xx0_mbus_win_offset, + .win_cfg_offset = mv78xx0_mbus_win_cfg_offset, .save_cpu_target = mvebu_mbus_default_save_cpu_target, + .win_remap_offset = generic_mbus_win_remap_8_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; static const struct of_device_id of_mvebu_mbus_ids[] = { { .compatible = "marvell,armada370-mbus", - .data = &armada_370_xp_mbus_data, }, + .data = &armada_370_mbus_data, }, + { .compatible = "marvell,armada375-mbus", + .data = &armada_xp_mbus_data, }, + { .compatible = "marvell,armada380-mbus", + .data = &armada_xp_mbus_data, }, { .compatible = "marvell,armadaxp-mbus", - .data = &armada_370_xp_mbus_data, }, + .data = &armada_xp_mbus_data, }, { .compatible = "marvell,kirkwood-mbus", .data = &kirkwood_mbus_data, }, { .compatible = "marvell,dove-mbus", @@ -789,15 +940,19 @@ static int mvebu_mbus_suspend(void) for (win = 0; win < s->soc->num_wins; win++) { void __iomem *addr = s->mbuswins_base + s->soc->win_cfg_offset(win); + void __iomem *addr_rmp; s->wins[win].base = readl(addr + WIN_BASE_OFF); s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF); - if (win >= s->soc->num_remappable_wins) + if (!mvebu_mbus_window_is_remappable(s, win)) continue; - s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF); - s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF); + addr_rmp = s->mbuswins_base + + s->soc->win_remap_offset(win); + + s->wins[win].remap_lo = readl(addr_rmp + WIN_REMAP_LO_OFF); + s->wins[win].remap_hi = readl(addr_rmp + WIN_REMAP_HI_OFF); } s->mbus_bridge_ctrl = readl(s->mbusbridge_base + @@ -821,15 +976,19 @@ static void mvebu_mbus_resume(void) for (win = 0; win < s->soc->num_wins; win++) { void __iomem *addr = s->mbuswins_base + s->soc->win_cfg_offset(win); + void __iomem *addr_rmp; writel(s->wins[win].base, addr + WIN_BASE_OFF); writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF); - if (win >= s->soc->num_remappable_wins) + if (!mvebu_mbus_window_is_remappable(s, win)) continue; - writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF); - writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF); + addr_rmp = s->mbuswins_base + + s->soc->win_remap_offset(win); + + writel(s->wins[win].remap_lo, addr_rmp + WIN_REMAP_LO_OFF); + writel(s->wins[win].remap_hi, addr_rmp + WIN_REMAP_HI_OFF); } } @@ -844,7 +1003,8 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, phys_addr_t sdramwins_phys_base, size_t sdramwins_size, phys_addr_t mbusbridge_phys_base, - size_t mbusbridge_size) + size_t mbusbridge_size, + bool is_coherent) { int win; @@ -876,6 +1036,10 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, mbus->soc->setup_cpu_target(mbus); + if (is_coherent) + writel(UNIT_SYNC_BARRIER_ALL, + mbus->mbuswins_base + UNIT_SYNC_BARRIER_OFF); + register_syscore_ops(&mvebu_mbus_syscore_ops); return 0; @@ -903,7 +1067,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, mbuswins_phys_base, mbuswins_size, sdramwins_phys_base, - sdramwins_size, 0, 0); + sdramwins_size, 0, 0, false); } #ifdef CONFIG_OF @@ -1105,7 +1269,8 @@ int __init mvebu_mbus_dt_init(bool is_coherent) sdramwins_res.start, resource_size(&sdramwins_res), mbusbridge_res.start, - resource_size(&mbusbridge_res)); + resource_size(&mbusbridge_res), + is_coherent); if (ret) return ret; diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 570202582dcf..1818f404538d 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -1226,6 +1226,7 @@ static void __init sun6i_init_clocks(struct device_node *node) ARRAY_SIZE(sun6i_critical_clocks)); } CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); +CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks); CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks); static void __init sun9i_init_clocks(struct device_node *node) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index fc01ec27d3c8..c062b6105d49 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -47,6 +47,9 @@ config SUN5I_HSTIMER select CLKSRC_MMIO bool +config TEGRA_TIMER + bool + config VT8500_TIMER bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 94d90b24b56b..ba9ebd868ec5 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o -obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o +obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 011a3363c265..c0d660f1aaac 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -81,6 +81,7 @@ static const struct of_device_id car_match[] __initconst = { { .compatible = "nvidia,tegra30-car", }, { .compatible = "nvidia,tegra114-car", }, { .compatible = "nvidia,tegra124-car", }, + { .compatible = "nvidia,tegra132-car", }, {}, }; diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 8646fa920d8d..4d2f71bf65c5 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -56,7 +56,7 @@ struct tegra_fuse_info { static void __iomem *fuse_base; static struct clk *fuse_clk; -static struct tegra_fuse_info *fuse_info; +static const struct tegra_fuse_info *fuse_info; u32 tegra30_fuse_readl(const unsigned int offset) { @@ -78,18 +78,18 @@ u32 tegra30_fuse_readl(const unsigned int offset) return val; } -static struct tegra_fuse_info tegra30_info = { +static const struct tegra_fuse_info tegra30_info = { .size = 0x2a4, .spare_bit = 0x144, .speedo_idx = SPEEDO_TEGRA30, }; -static struct tegra_fuse_info tegra114_info = { +static const struct tegra_fuse_info tegra114_info = { .size = 0x2a0, .speedo_idx = SPEEDO_TEGRA114, }; -static struct tegra_fuse_info tegra124_info = { +static const struct tegra_fuse_info tegra124_info = { .size = 0x300, .speedo_idx = SPEEDO_TEGRA124, }; @@ -182,6 +182,7 @@ static void __init legacy_fuse_init(void) fuse_info = &tegra114_info; break; case TEGRA124: + case TEGRA132: fuse_info = &tegra124_info; break; default: diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index a2c0ceb95f8f..c956395cf46f 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -70,6 +70,10 @@ #define PMC_SCRATCH41 0x140 +#define PMC_SENSOR_CTRL 0x1b0 +#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) +#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) + #define IO_DPD_REQ 0x1b8 #define IO_DPD_REQ_CODE_IDLE (0 << 30) #define IO_DPD_REQ_CODE_OFF (1 << 30) @@ -81,6 +85,18 @@ #define IO_DPD2_STATUS 0x1c4 #define SEL_DPD_TIM 0x1c8 +#define PMC_SCRATCH54 0x258 +#define PMC_SCRATCH54_DATA_SHIFT 8 +#define PMC_SCRATCH54_ADDR_SHIFT 0 + +#define PMC_SCRATCH55 0x25c +#define PMC_SCRATCH55_RESET_TEGRA (1 << 31) +#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 +#define PMC_SCRATCH55_PINMUX_SHIFT 24 +#define PMC_SCRATCH55_16BITOP (1 << 15) +#define PMC_SCRATCH55_CHECKSUM_SHIFT 16 +#define PMC_SCRATCH55_I2CSLV1_SHIFT 0 + #define GPU_RG_CNTRL 0x2d4 struct tegra_pmc_soc { @@ -88,6 +104,9 @@ struct tegra_pmc_soc { const char *const *powergates; unsigned int num_cpu_powergates; const u8 *cpu_powergates; + + bool has_tsense_reset; + bool has_gpu_clamps; }; /** @@ -110,6 +129,7 @@ struct tegra_pmc_soc { * @powergates_lock: mutex for power gate register access */ struct tegra_pmc { + struct device *dev; void __iomem *base; struct clk *clk; @@ -225,11 +245,11 @@ int tegra_powergate_remove_clamping(int id) return -EINVAL; /* - * The Tegra124 GPU has a separate register (with different semantics) - * to remove clamps. + * On Tegra124 and later, the clamps for the GPU are controlled by a + * separate register (with different semantics). */ - if (tegra_get_chip_id() == TEGRA124) { - if (id == TEGRA_POWERGATE_3D) { + if (id == TEGRA_POWERGATE_3D) { + if (pmc->soc->has_gpu_clamps) { tegra_pmc_writel(0, GPU_RG_CNTRL); return 0; } @@ -703,6 +723,83 @@ static void tegra_pmc_init(struct tegra_pmc *pmc) tegra_pmc_writel(value, PMC_CNTRL); } +void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) +{ + static const char disabled[] = "emergency thermal reset disabled"; + u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux; + struct device *dev = pmc->dev; + struct device_node *np; + u32 value, checksum; + + if (!pmc->soc->has_tsense_reset) + goto out; + + np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip"); + if (!np) { + dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled); + goto out; + } + + if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) { + dev_err(dev, "I2C controller ID missing, %s.\n", disabled); + goto out; + } + + if (of_property_read_u32(np, "nvidia,bus-addr", &pmu_addr)) { + dev_err(dev, "nvidia,bus-addr missing, %s.\n", disabled); + goto out; + } + + if (of_property_read_u32(np, "nvidia,reg-addr", ®_addr)) { + dev_err(dev, "nvidia,reg-addr missing, %s.\n", disabled); + goto out; + } + + if (of_property_read_u32(np, "nvidia,reg-data", ®_data)) { + dev_err(dev, "nvidia,reg-data missing, %s.\n", disabled); + goto out; + } + + if (of_property_read_u32(np, "nvidia,pinmux-id", &pinmux)) + pinmux = 0; + + value = tegra_pmc_readl(PMC_SENSOR_CTRL); + value |= PMC_SENSOR_CTRL_SCRATCH_WRITE; + tegra_pmc_writel(value, PMC_SENSOR_CTRL); + + value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) | + (reg_addr << PMC_SCRATCH54_ADDR_SHIFT); + tegra_pmc_writel(value, PMC_SCRATCH54); + + value = PMC_SCRATCH55_RESET_TEGRA; + value |= ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT; + value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT; + value |= pmu_addr << PMC_SCRATCH55_I2CSLV1_SHIFT; + + /* + * Calculate checksum of SCRATCH54, SCRATCH55 fields. Bits 23:16 will + * contain the checksum and are currently zero, so they are not added. + */ + checksum = reg_addr + reg_data + (value & 0xff) + ((value >> 8) & 0xff) + + ((value >> 24) & 0xff); + checksum &= 0xff; + checksum = 0x100 - checksum; + + value |= checksum << PMC_SCRATCH55_CHECKSUM_SHIFT; + + tegra_pmc_writel(value, PMC_SCRATCH55); + + value = tegra_pmc_readl(PMC_SENSOR_CTRL); + value |= PMC_SENSOR_CTRL_ENABLE_RST; + tegra_pmc_writel(value, PMC_SENSOR_CTRL); + + dev_info(pmc->dev, "emergency thermal reset enabled\n"); + +out: + of_node_put(np); + return; +} + static int tegra_pmc_probe(struct platform_device *pdev) { void __iomem *base = pmc->base; @@ -728,8 +825,12 @@ static int tegra_pmc_probe(struct platform_device *pdev) return err; } + pmc->dev = &pdev->dev; + tegra_pmc_init(pmc); + tegra_pmc_init_tsense_reset(pmc); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_powergate_debugfs_init(); if (err < 0) @@ -739,7 +840,7 @@ static int tegra_pmc_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP +#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) static int tegra_pmc_suspend(struct device *dev) { tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41); @@ -753,10 +854,11 @@ static int tegra_pmc_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); +#endif + static const char * const tegra20_powergates[] = { [TEGRA_POWERGATE_CPU] = "cpu", [TEGRA_POWERGATE_3D] = "3d", @@ -772,6 +874,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .powergates = tegra20_powergates, .num_cpu_powergates = 0, .cpu_powergates = NULL, + .has_tsense_reset = false, + .has_gpu_clamps = false, }; static const char * const tegra30_powergates[] = { @@ -803,6 +907,8 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .powergates = tegra30_powergates, .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), .cpu_powergates = tegra30_cpu_powergates, + .has_tsense_reset = true, + .has_gpu_clamps = false, }; static const char * const tegra114_powergates[] = { @@ -838,6 +944,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .powergates = tegra114_powergates, .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), .cpu_powergates = tegra114_cpu_powergates, + .has_tsense_reset = true, + .has_gpu_clamps = false, }; static const char * const tegra124_powergates[] = { @@ -879,6 +987,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .powergates = tegra124_powergates, .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), .cpu_powergates = tegra124_cpu_powergates, + .has_tsense_reset = true, + .has_gpu_clamps = true, }; static const struct of_device_id tegra_pmc_match[] = { @@ -894,7 +1004,9 @@ static struct platform_driver tegra_pmc_driver = { .name = "tegra-pmc", .suppress_bind_attrs = true, .of_match_table = tegra_pmc_match, +#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) .pm = &tegra_pmc_pm_ops, +#endif }, .probe = tegra_pmc_probe, }; |