diff options
95 files changed, 2254 insertions, 999 deletions
diff --git a/Documentation/devicetree/bindings/clock/imx5-clock.txt b/Documentation/devicetree/bindings/clock/imx5-clock.txt index 2a0c904c46a..d71b4b2c077 100644 --- a/Documentation/devicetree/bindings/clock/imx5-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx5-clock.txt @@ -38,7 +38,6 @@ clocks and IDs.  	usb_phy_podf		23  	cpu_podf		24  	di_pred			25 -	tve_di			26  	tve_s			27  	uart1_ipg_gate		28  	uart1_per_gate		29 @@ -172,6 +171,19 @@ clocks and IDs.  	can1_serial_gate	157  	can1_ipg_gate		158  	owire_gate		159 +	gpu3d_s			160 +	gpu2d_s			161 +	gpu3d_gate		162 +	gpu2d_gate		163 +	garb_gate		164 +	cko1_sel		165 +	cko1_podf		166 +	cko1			167 +	cko2_sel		168 +	cko2_podf		169 +	cko2			170 +	srtc_gate		171 +	pata_gate		172  Examples (for mx53): diff --git a/Documentation/devicetree/bindings/clock/imx6q-clock.txt b/Documentation/devicetree/bindings/clock/imx6q-clock.txt index 969b38e06ad..6deb6fd1c7c 100644 --- a/Documentation/devicetree/bindings/clock/imx6q-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx6q-clock.txt @@ -205,6 +205,9 @@ clocks and IDs.  	enet_ref		190  	usbphy1_gate		191  	usbphy2_gate		192 +	pll4_post_div		193 +	pll5_post_div		194 +	pll5_video_div		195  Examples: diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.txt b/Documentation/devicetree/bindings/reset/fsl,imx-src.txt new file mode 100644 index 00000000000..13301777e11 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/fsl,imx-src.txt @@ -0,0 +1,49 @@ +Freescale i.MX System Reset Controller +====================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "fsl,<chip>-src" +- reg: should be register base and length as documented in the +  datasheet +- interrupts: Should contain SRC interrupt and CPU WDOG interrupt, +  in this order. +- #reset-cells: 1, see below + +example: + +src: src@020d8000 { +        compatible = "fsl,imx6q-src"; +        reg = <0x020d8000 0x4000>; +        interrupts = <0 91 0x04 0 96 0x04>; +        #reset-cells = <1>; +}; + +Specifying reset lines connected to IP modules +============================================== + +The system reset controller can be used to reset the GPU, VPU, +IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device +nodes should specify the reset line on the SRC in their resets +property, containing a phandle to the SRC device node and a +RESET_INDEX specifying which module to reset, as described in +reset.txt + +example: + +        ipu1: ipu@02400000 { +                resets = <&src 2>; +        }; +        ipu2: ipu@02800000 { +                resets = <&src 4>; +        }; + +The following RESET_INDEX values are valid for i.MX5: +GPU_RESET     0 +VPU_RESET     1 +IPU1_RESET    2 +OPEN_VG_RESET 3 +The following additional RESET_INDEX value is valid for i.MX6: +IPU2_RESET    4 diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt index 8071ac20d4b..b876d4925a5 100644 --- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt +++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt @@ -8,6 +8,8 @@ Required properties:  - interrupts: Should contain sync interrupt and error interrupt,    in this order.  - #crtc-cells: 1, See below +- resets: phandle pointing to the system reset controller and +          reset line index, see reset/fsl,imx-src.txt for details  example: @@ -16,6 +18,7 @@ ipu: ipu@18000000 {  	compatible = "fsl,imx53-ipu";  	reg = <0x18000000 0x080000000>;  	interrupts = <11 10>; +	resets = <&src 2>;  };  Parallel display support diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5c56fa8824e..18bef301d6e 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -498,6 +498,7 @@ config ARCH_DOVE  	select PINCTRL_DOVE  	select PLAT_ORION_LEGACY  	select USB_ARCH_HAS_EHCI +	select MVEBU_MBUS  	help  	  Support for the Marvell Dove SoC 88AP510 @@ -511,6 +512,7 @@ config ARCH_KIRKWOOD  	select PINCTRL  	select PINCTRL_KIRKWOOD  	select PLAT_ORION_LEGACY +	select MVEBU_MBUS  	help  	  Support for the following Marvell Kirkwood series SoCs:  	  88F6180, 88F6192 and 88F6281. @@ -522,6 +524,7 @@ config ARCH_MV78XX0  	select GENERIC_CLOCKEVENTS  	select PCI  	select PLAT_ORION_LEGACY +	select MVEBU_MBUS  	help  	  Support for the following Marvell MV78xx0 series SoCs:  	  MV781x0, MV782x0. @@ -534,6 +537,7 @@ config ARCH_ORION5X  	select GENERIC_CLOCKEVENTS  	select PCI  	select PLAT_ORION_LEGACY +	select MVEBU_MBUS  	help  	  Support for the following Marvell Orion 5x series SoCs:  	  Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182), diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index f57a6ba26e0..1d41908d5cd 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -245,11 +245,11 @@ choice  		  on i.MX53.  	config DEBUG_IMX6Q_UART -		bool "i.MX6Q Debug UART" +		bool "i.MX6Q/DL Debug UART"  		depends on SOC_IMX6Q  		help  		  Say Y here if you want kernel low-level debugging support -		  on i.MX6Q. +		  on i.MX6Q/DL.  	config DEBUG_MMP_UART2  		bool "Kernel low-level debugging message via MMP UART2" diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index 758c4ea9034..9693f796bcf 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -73,11 +73,6 @@  			       clocks = <&coreclk 2>;  		}; -		addr-decoding@d0020000 { -			compatible = "marvell,armada-addr-decoding-controller"; -			reg = <0xd0020000 0x258>; -		}; -  		sata@d00a0000 {  			compatible = "marvell,orion-sata";  			reg = <0xd00a0000 0x2400>; diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 748fc347ed1..14fb2e609ba 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi @@ -136,5 +136,12 @@  			clock-names = "cpu_1x";  			clock-ranges;  		}; +		scutimer: scutimer@f8f00600 { +			interrupt-parent = <&intc>; +			interrupts = < 1 13 0x301 >; +			compatible = "arm,cortex-a9-twd-timer"; +			reg = < 0xf8f00600 0x20 >; +			clocks = <&cpu_clk 1>; +		} ;  	};  }; diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index 02c657af400..f07a847b00c 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -109,6 +109,7 @@ CONFIG_I2C_IMX=y  CONFIG_SPI=y  CONFIG_SPI_IMX=y  CONFIG_SPI_SPIDEV=y +CONFIG_GPIO_SYSFS=y  CONFIG_W1=y  CONFIG_W1_MASTER_MXC=y  CONFIG_W1_SLAVE_THERM=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 088d6c11a0f..6ec010f248b 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -9,6 +9,7 @@ CONFIG_CGROUPS=y  CONFIG_RELAY=y  CONFIG_BLK_DEV_INITRD=y  CONFIG_EXPERT=y +CONFIG_PERF_EVENTS=y  # CONFIG_SLUB_DEBUG is not set  # CONFIG_COMPAT_BRK is not set  CONFIG_MODULES=y diff --git a/arch/arm/include/debug/mvebu.S b/arch/arm/include/debug/mvebu.S index 865c6d02b33..df191afa3be 100644 --- a/arch/arm/include/debug/mvebu.S +++ b/arch/arm/include/debug/mvebu.S @@ -12,7 +12,7 @@  */  #define ARMADA_370_XP_REGS_PHYS_BASE	0xd0000000 -#define ARMADA_370_XP_REGS_VIRT_BASE	0xfeb00000 +#define ARMADA_370_XP_REGS_VIRT_BASE	0xfec00000  	.macro	addruart, rp, rv, tmp  	ldr	\rp, =ARMADA_370_XP_REGS_PHYS_BASE diff --git a/arch/arm/mach-dove/Makefile b/arch/arm/mach-dove/Makefile index 3f0a858fb59..4d9d2ffc453 100644 --- a/arch/arm/mach-dove/Makefile +++ b/arch/arm/mach-dove/Makefile @@ -1,4 +1,4 @@ -obj-y				+= common.o addr-map.o irq.o +obj-y				+= common.o irq.o  obj-$(CONFIG_DOVE_LEGACY)	+= mpp.o  obj-$(CONFIG_PCI)		+= pcie.o  obj-$(CONFIG_MACH_DOVE_DB)	+= dove-db-setup.o diff --git a/arch/arm/mach-dove/addr-map.c b/arch/arm/mach-dove/addr-map.c deleted file mode 100644 index 2a06c016341..00000000000 --- a/arch/arm/mach-dove/addr-map.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * arch/arm/mach-dove/addr-map.c - * - * Address map functions for Marvell Dove 88AP510 SoC - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mbus.h> -#include <linux/io.h> -#include <asm/mach/arch.h> -#include <asm/setup.h> -#include <mach/dove.h> -#include <plat/addr-map.h> -#include "common.h" - -/* - * Generic Address Decode Windows bit settings - */ -#define TARGET_DDR		0x0 -#define TARGET_BOOTROM		0x1 -#define TARGET_CESA		0x3 -#define TARGET_PCIE0		0x4 -#define TARGET_PCIE1		0x8 -#define TARGET_SCRATCHPAD	0xd - -#define ATTR_CESA		0x01 -#define ATTR_BOOTROM		0xfd -#define ATTR_DEV_SPI0_ROM	0xfe -#define ATTR_DEV_SPI1_ROM	0xfb -#define ATTR_PCIE_IO		0xe0 -#define ATTR_PCIE_MEM		0xe8 -#define ATTR_SCRATCHPAD		0x0 - -static inline void __iomem *ddr_map_sc(int i) -{ -	return (void __iomem *)(DOVE_MC_VIRT_BASE + 0x100 + ((i) << 4)); -} - -/* - * Description of the windows needed by the platform code - */ -static struct __initdata orion_addr_map_cfg addr_map_cfg = { -	.num_wins = 8, -	.remappable_wins = 4, -	.bridge_virt_base = BRIDGE_VIRT_BASE, -}; - -static const struct __initdata orion_addr_map_info addr_map_info[] = { -	/* -	 * Windows for PCIe IO+MEM space. -	 */ -	{ 0, DOVE_PCIE0_IO_PHYS_BASE, DOVE_PCIE0_IO_SIZE, -	  TARGET_PCIE0, ATTR_PCIE_IO, DOVE_PCIE0_IO_BUS_BASE -	}, -	{ 1, DOVE_PCIE1_IO_PHYS_BASE, DOVE_PCIE1_IO_SIZE, -	  TARGET_PCIE1, ATTR_PCIE_IO, DOVE_PCIE1_IO_BUS_BASE -	}, -	{ 2, DOVE_PCIE0_MEM_PHYS_BASE, DOVE_PCIE0_MEM_SIZE, -	  TARGET_PCIE0, ATTR_PCIE_MEM, -1 -	}, -	{ 3, DOVE_PCIE1_MEM_PHYS_BASE, DOVE_PCIE1_MEM_SIZE, -	  TARGET_PCIE1, ATTR_PCIE_MEM, -1 -	}, -	/* -	 * Window for CESA engine. -	 */ -	{ 4, DOVE_CESA_PHYS_BASE, DOVE_CESA_SIZE, -	  TARGET_CESA, ATTR_CESA, -1 -	}, -	/* -	 * Window to the BootROM for Standby and Sleep Resume -	 */ -	{ 5, DOVE_BOOTROM_PHYS_BASE, DOVE_BOOTROM_SIZE, -	  TARGET_BOOTROM, ATTR_BOOTROM, -1 -	}, -	/* -	 * Window to the PMU Scratch Pad space -	 */ -	{ 6, DOVE_SCRATCHPAD_PHYS_BASE, DOVE_SCRATCHPAD_SIZE, -	  TARGET_SCRATCHPAD, ATTR_SCRATCHPAD, -1 -	}, -	/* End marker */ -	{ -1, 0, 0, 0, 0, 0 } -}; - -void __init dove_setup_cpu_mbus(void) -{ -	int i; -	int cs; - -	/* -	 * Disable, clear and configure windows. -	 */ -	orion_config_wins(&addr_map_cfg, addr_map_info); - -	/* -	 * Setup MBUS dram target info. -	 */ -	orion_mbus_dram_info.mbus_dram_target_id = TARGET_DDR; - -	for (i = 0, cs = 0; i < 2; i++) { -		u32 map = readl(ddr_map_sc(i)); - -		/* -		 * Chip select enabled? -		 */ -		if (map & 1) { -			struct mbus_dram_window *w; - -			w = &orion_mbus_dram_info.cs[cs++]; -			w->cs_index = i; -			w->mbus_attr = 0; /* CS address decoding done inside */ -					  /* the DDR controller, no need to  */ -					  /* provide attributes */ -			w->base = map & 0xff800000; -			w->size = 0x100000 << (((map & 0x000f0000) >> 16) - 4); -		} -	} -	orion_mbus_dram_info.num_cs = cs; -} diff --git a/arch/arm/mach-dove/board-dt.c b/arch/arm/mach-dove/board-dt.c index fbde1dd6711..0b142803b2e 100644 --- a/arch/arm/mach-dove/board-dt.c +++ b/arch/arm/mach-dove/board-dt.c @@ -64,7 +64,7 @@ static void __init dove_dt_init(void)  #ifdef CONFIG_CACHE_TAUROS2  	tauros2_init(0);  #endif -	dove_setup_cpu_mbus(); +	dove_setup_cpu_wins();  	/* Setup root of clk tree */  	dove_of_clk_init(); diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index c6b3b2bb50e..e2b5da031f9 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -224,6 +224,9 @@ void __init dove_i2c_init(void)  void __init dove_init_early(void)  {  	orion_time_set_base(TIMER_VIRT_BASE); +	mvebu_mbus_init("marvell,dove-mbus", +			BRIDGE_WINS_BASE, BRIDGE_WINS_SZ, +			DOVE_MC_WINS_BASE, DOVE_MC_WINS_SZ);  }  static int __init dove_find_tclk(void) @@ -326,6 +329,40 @@ void __init dove_sdio1_init(void)  	platform_device_register(&dove_sdio1);  } +void __init dove_setup_cpu_wins(void) +{ +	/* +	 * The PCIe windows will no longer be statically allocated +	 * here once Dove is migrated to the pci-mvebu driver. +	 */ +	mvebu_mbus_add_window_remap_flags("pcie0.0", +					  DOVE_PCIE0_IO_PHYS_BASE, +					  DOVE_PCIE0_IO_SIZE, +					  DOVE_PCIE0_IO_BUS_BASE, +					  MVEBU_MBUS_PCI_IO); +	mvebu_mbus_add_window_remap_flags("pcie1.0", +					  DOVE_PCIE1_IO_PHYS_BASE, +					  DOVE_PCIE1_IO_SIZE, +					  DOVE_PCIE1_IO_BUS_BASE, +					  MVEBU_MBUS_PCI_IO); +	mvebu_mbus_add_window_remap_flags("pcie0.0", +					  DOVE_PCIE0_MEM_PHYS_BASE, +					  DOVE_PCIE0_MEM_SIZE, +					  MVEBU_MBUS_NO_REMAP, +					  MVEBU_MBUS_PCI_MEM); +	mvebu_mbus_add_window_remap_flags("pcie1.0", +					  DOVE_PCIE1_MEM_PHYS_BASE, +					  DOVE_PCIE1_MEM_SIZE, +					  MVEBU_MBUS_NO_REMAP, +					  MVEBU_MBUS_PCI_MEM); +	mvebu_mbus_add_window("cesa", DOVE_CESA_PHYS_BASE, +			      DOVE_CESA_SIZE); +	mvebu_mbus_add_window("bootrom", DOVE_BOOTROM_PHYS_BASE, +			      DOVE_BOOTROM_SIZE); +	mvebu_mbus_add_window("scratchpad", DOVE_SCRATCHPAD_PHYS_BASE, +			      DOVE_SCRATCHPAD_SIZE); +} +  void __init dove_init(void)  {  	pr_info("Dove 88AP510 SoC, TCLK = %d MHz.\n", @@ -334,7 +371,7 @@ void __init dove_init(void)  #ifdef CONFIG_CACHE_TAUROS2  	tauros2_init(0);  #endif -	dove_setup_cpu_mbus(); +	dove_setup_cpu_wins();  	/* Setup root of clk tree */  	dove_clk_init(); diff --git a/arch/arm/mach-dove/common.h b/arch/arm/mach-dove/common.h index ee59fba4c6d..e86347928b6 100644 --- a/arch/arm/mach-dove/common.h +++ b/arch/arm/mach-dove/common.h @@ -23,7 +23,7 @@ void dove_map_io(void);  void dove_init(void);  void dove_init_early(void);  void dove_init_irq(void); -void dove_setup_cpu_mbus(void); +void dove_setup_cpu_wins(void);  void dove_ge00_init(struct mv643xx_eth_platform_data *eth_data);  void dove_sata_init(struct mv_sata_platform_data *sata_data);  #ifdef CONFIG_PCI diff --git a/arch/arm/mach-dove/include/mach/dove.h b/arch/arm/mach-dove/include/mach/dove.h index 661725e3115..0c4b35f4ee5 100644 --- a/arch/arm/mach-dove/include/mach/dove.h +++ b/arch/arm/mach-dove/include/mach/dove.h @@ -77,6 +77,8 @@  /* North-South Bridge */  #define BRIDGE_VIRT_BASE	(DOVE_SB_REGS_VIRT_BASE + 0x20000)  #define BRIDGE_PHYS_BASE	(DOVE_SB_REGS_PHYS_BASE + 0x20000) +#define  BRIDGE_WINS_BASE       (BRIDGE_PHYS_BASE) +#define  BRIDGE_WINS_SZ         (0x80)  /* Cryptographic Engine */  #define DOVE_CRYPT_PHYS_BASE	(DOVE_SB_REGS_PHYS_BASE + 0x30000) @@ -168,6 +170,9 @@  #define  DOVE_SSP_CLOCK_ENABLE		(1 << 1)  #define  DOVE_SSP_BPB_CLOCK_SRC_SSP	(1 << 11)  /* Memory Controller */ +#define DOVE_MC_PHYS_BASE       (DOVE_NB_REGS_PHYS_BASE + 0x00000) +#define  DOVE_MC_WINS_BASE      (DOVE_MC_PHYS_BASE + 0x100) +#define  DOVE_MC_WINS_SZ        (0x8)  #define DOVE_MC_VIRT_BASE	(DOVE_NB_REGS_VIRT_BASE + 0x00000)  /* LCD Controller */ diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 2ebc97e16b9..78f795d73cb 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -65,6 +65,9 @@ config IRAM_ALLOC  	bool  	select GENERIC_ALLOCATOR +config HAVE_IMX_ANATOP +	bool +  config HAVE_IMX_GPC  	bool @@ -73,6 +76,7 @@ config HAVE_IMX_MMDC  config HAVE_IMX_SRC  	def_bool y if SMP +	select ARCH_HAS_RESET_CONTROLLER  config IMX_HAVE_IOMUX_V1  	bool @@ -115,6 +119,8 @@ config SOC_IMX25  config SOC_IMX27  	bool +	select ARCH_HAS_CPUFREQ +	select ARCH_HAS_OPP  	select COMMON_CLK  	select CPU_ARM926T  	select IMX_HAVE_IOMUX_V1 @@ -142,6 +148,7 @@ config SOC_IMX35  config SOC_IMX5  	bool  	select ARCH_HAS_CPUFREQ +	select ARCH_HAS_OPP  	select ARCH_MXC_IOMUX_V3  	select COMMON_CLK  	select CPU_V7 @@ -783,7 +790,7 @@ config	SOC_IMX53  	  This enables support for Freescale i.MX53 processor.  config SOC_IMX6Q -	bool "i.MX6 Quad support" +	bool "i.MX6 Quad/DualLite support"  	select ARCH_HAS_CPUFREQ  	select ARCH_HAS_OPP  	select ARM_CPU_SUSPEND if PM @@ -796,6 +803,7 @@ config SOC_IMX6Q  	select HAVE_ARM_SCU if SMP  	select HAVE_ARM_TWD if LOCAL_TIMERS  	select HAVE_CAN_FLEXCAN if CAN +	select HAVE_IMX_ANATOP  	select HAVE_IMX_GPC  	select HAVE_IMX_MMDC  	select HAVE_IMX_SRC diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index fbe60a14534..930958973f8 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_MACH_EUKREA_CPUIMX35SD) += mach-cpuimx35.o  obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o  obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o +obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o  obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o  obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o  obj-$(CONFIG_HAVE_IMX_SRC) += src.o diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c new file mode 100644 index 00000000000..0cfa07dd9aa --- /dev/null +++ b/arch/arm/mach-imx/anatop.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include "common.h" + +#define REG_SET		0x4 +#define REG_CLR		0x8 + +#define ANADIG_REG_2P5		0x130 +#define ANADIG_REG_CORE		0x140 +#define ANADIG_ANA_MISC0	0x150 +#define ANADIG_USB1_CHRG_DETECT	0x1b0 +#define ANADIG_USB2_CHRG_DETECT	0x210 +#define ANADIG_DIGPROG		0x260 + +#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG	0x40000 +#define BM_ANADIG_REG_CORE_FET_ODRIVE		0x20000000 +#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG	0x1000 +#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B	0x80000 +#define BM_ANADIG_USB_CHRG_DETECT_EN_B		0x100000 + +static struct regmap *anatop; + +static void imx_anatop_enable_weak2p5(bool enable) +{ +	u32 reg, val; + +	regmap_read(anatop, ANADIG_ANA_MISC0, &val); + +	/* can only be enabled when stop_mode_config is clear. */ +	reg = ANADIG_REG_2P5; +	reg += (enable && (val & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) ? +		REG_SET : REG_CLR; +	regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG); +} + +static void imx_anatop_enable_fet_odrive(bool enable) +{ +	regmap_write(anatop, ANADIG_REG_CORE + (enable ? REG_SET : REG_CLR), +		BM_ANADIG_REG_CORE_FET_ODRIVE); +} + +void imx_anatop_pre_suspend(void) +{ +	imx_anatop_enable_weak2p5(true); +	imx_anatop_enable_fet_odrive(true); +} + +void imx_anatop_post_resume(void) +{ +	imx_anatop_enable_fet_odrive(false); +	imx_anatop_enable_weak2p5(false); +} + +void imx_anatop_usb_chrg_detect_disable(void) +{ +	regmap_write(anatop, ANADIG_USB1_CHRG_DETECT, +		BM_ANADIG_USB_CHRG_DETECT_EN_B +		| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); +	regmap_write(anatop, ANADIG_USB2_CHRG_DETECT, +		BM_ANADIG_USB_CHRG_DETECT_EN_B | +		BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); +} + +u32 imx_anatop_get_digprog(void) +{ +	struct device_node *np; +	void __iomem *anatop_base; +	static u32 digprog; + +	if (digprog) +		return digprog; + +	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); +	anatop_base = of_iomap(np, 0); +	WARN_ON(!anatop_base); +	digprog = readl_relaxed(anatop_base + ANADIG_DIGPROG); + +	return digprog; +} + +void __init imx_anatop_init(void) +{ +	anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop"); +	if (IS_ERR(anatop)) { +		pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__); +		return; +	} +} diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 2bc623b414c..6fc486b6a3c 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -45,16 +45,40 @@ static const char *mx53_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "  static const char *mx53_ldb_di1_sel[] = { "pll3_sw", "pll4_sw", };  static const char *mx51_tve_ext_sel[] = { "osc", "ckih1", };  static const char *mx53_tve_ext_sel[] = { "pll4_sw", "ckih1", }; -static const char *tve_sel[] = { "tve_pred", "tve_ext_sel", }; +static const char *mx51_tve_sel[] = { "tve_pred", "tve_ext_sel", };  static const char *ipu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", }; +static const char *gpu3d_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb" }; +static const char *gpu2d_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb" };  static const char *vpu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", };  static const char *mx53_can_sel[] = { "ipg", "ckih1", "ckih2", "lp_apm", }; +static const char *mx53_cko1_sel[] = { +	"cpu_podf", "pll1_sw", "pll2_sw", "pll3_sw", +	"emi_slow_podf", "pll4_sw", "nfc_podf", "dummy", +	"di_pred", "dummy", "dummy", "ahb", +	"ipg", "per_root", "ckil", "dummy",}; +static const char *mx53_cko2_sel[] = { +	"dummy"/* dptc_core */, "dummy"/* dptc_perich */, +	"dummy", "esdhc_a_podf", +	"usboh3_podf", "dummy"/* wrck_clk_root */, +	"ecspi_podf", "dummy"/* pll1_ref_clk */, +	"esdhc_b_podf", "dummy"/* ddr_clk_root */, +	"dummy"/* arm_axi_clk_root */, "dummy"/* usb_phy_out */, +	"vpu_sel", "ipu_sel", +	"osc", "ckih1", +	"dummy", "esdhc_c_sel", +	"ssi1_root_podf", "ssi2_root_podf", +	"dummy", "dummy", +	"dummy"/* lpsr_clk_root */, "dummy"/* pgc_clk_root */, +	"dummy"/* tve_out */, "usb_phy_sel", +	"tve_sel", "lp_apm", +	"uart_root", "dummy"/* spdif0_clk_root */, +	"dummy", "dummy", };  enum imx5_clks {  	dummy, ckil, osc, ckih1, ckih2, ahb, ipg, axi_a, axi_b, uart_pred,  	uart_root, esdhc_a_pred, esdhc_b_pred, esdhc_c_s, esdhc_d_s,  	emi_sel, emi_slow_podf, nfc_podf, ecspi_pred, ecspi_podf, usboh3_pred, -	usboh3_podf, usb_phy_pred, usb_phy_podf, cpu_podf, di_pred, tve_di, +	usboh3_podf, usb_phy_pred, usb_phy_podf, cpu_podf, di_pred, tve_di_unused,  	tve_s, uart1_ipg_gate, uart1_per_gate, uart2_ipg_gate,  	uart2_per_gate, uart3_ipg_gate, uart3_per_gate, i2c1_gate, i2c2_gate,  	gpt_ipg_gate, pwm1_ipg_gate, pwm1_hf_gate, pwm2_ipg_gate, pwm2_hf_gate, @@ -83,7 +107,10 @@ enum imx5_clks {  	ssi2_root_gate, ssi3_root_gate, ssi_ext1_gate, ssi_ext2_gate,  	epit1_ipg_gate, epit1_hf_gate, epit2_ipg_gate, epit2_hf_gate,  	can_sel, can1_serial_gate, can1_ipg_gate, -	owire_gate, +	owire_gate, gpu3d_s, gpu2d_s, gpu3d_gate, gpu2d_gate, garb_gate, +	cko1_sel, cko1_podf, cko1, +	cko2_sel, cko2_podf, cko2, +	srtc_gate, pata_gate,  	clk_max  }; @@ -160,8 +187,6 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,  				usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str));  	clk[cpu_podf] = imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3);  	clk[di_pred] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3); -	clk[tve_di] = imx_clk_fixed("tve_di", 65000000); /* FIXME */ -	clk[tve_s] = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1, tve_sel, ARRAY_SIZE(tve_sel));  	clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30);  	clk[uart1_ipg_gate] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6);  	clk[uart1_per_gate] = imx_clk_gate2("uart1_per_gate", "uart_root", MXC_CCM_CCGR1, 8); @@ -200,6 +225,11 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,  	clk[nfc_gate] = imx_clk_gate2("nfc_gate", "nfc_podf", MXC_CCM_CCGR5, 20);  	clk[ipu_di0_gate] = imx_clk_gate2("ipu_di0_gate", "ipu_di0_sel", MXC_CCM_CCGR6, 10);  	clk[ipu_di1_gate] = imx_clk_gate2("ipu_di1_gate", "ipu_di1_sel", MXC_CCM_CCGR6, 12); +	clk[gpu3d_s] = imx_clk_mux("gpu3d_sel", MXC_CCM_CBCMR, 4, 2, gpu3d_sel, ARRAY_SIZE(gpu3d_sel)); +	clk[gpu2d_s] = imx_clk_mux("gpu2d_sel", MXC_CCM_CBCMR, 16, 2, gpu2d_sel, ARRAY_SIZE(gpu2d_sel)); +	clk[gpu3d_gate] = imx_clk_gate2("gpu3d_gate", "gpu3d_sel", MXC_CCM_CCGR5, 2); +	clk[garb_gate] = imx_clk_gate2("garb_gate", "axi_a", MXC_CCM_CCGR5, 4); +	clk[gpu2d_gate] = imx_clk_gate2("gpu2d_gate", "gpu2d_sel", MXC_CCM_CCGR6, 14);  	clk[vpu_s] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel));  	clk[vpu_gate] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6);  	clk[vpu_reference_gate] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8); @@ -235,6 +265,8 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,  	clk[epit2_ipg_gate] = imx_clk_gate2("epit2_ipg_gate", "ipg", MXC_CCM_CCGR2, 6);  	clk[epit2_hf_gate] = imx_clk_gate2("epit2_hf_gate", "per_root", MXC_CCM_CCGR2, 8);  	clk[owire_gate] = imx_clk_gate2("owire_gate", "per_root", MXC_CCM_CCGR2, 22); +	clk[srtc_gate] = imx_clk_gate2("srtc_gate", "per_root", MXC_CCM_CCGR4, 28); +	clk[pata_gate] = imx_clk_gate2("pata_gate", "ipg", MXC_CCM_CCGR4, 0);  	for (i = 0; i < ARRAY_SIZE(clk); i++)  		if (IS_ERR(clk[i])) @@ -286,7 +318,6 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,  	clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.0");  	clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.1");  	clk_register_clkdev(clk[dummy], NULL, "imx-keypad"); -	clk_register_clkdev(clk[tve_gate], NULL, "imx-tve.0");  	clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx-tve.0");  	clk_register_clkdev(clk[gpc_dvfs], "gpc_dvfs", NULL);  	clk_register_clkdev(clk[epit1_ipg_gate], "ipg", "imx-epit.0"); @@ -331,8 +362,10 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,  				mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel));  	clk[ipu_di1_sel] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,  				mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel)); -	clk[tve_ext_sel] = imx_clk_mux("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, -				mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel)); +	clk[tve_ext_sel] = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, +				mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel), CLK_SET_RATE_PARENT); +	clk[tve_s] = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1, +				mx51_tve_sel, ARRAY_SIZE(mx51_tve_sel));  	clk[tve_gate] = imx_clk_gate2("tve_gate", "tve_sel", MXC_CCM_CCGR2, 30);  	clk[tve_pred] = imx_clk_divider("tve_pred", "pll3_sw", MXC_CCM_CDCDR, 28, 3);  	clk[esdhc1_per_gate] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); @@ -420,23 +453,23 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,  	clk[pll3_sw] = imx_clk_pllv2("pll3_sw", "osc", MX53_DPLL3_BASE);  	clk[pll4_sw] = imx_clk_pllv2("pll4_sw", "osc", MX53_DPLL4_BASE); -	clk[ldb_di1_sel] = imx_clk_mux("ldb_di1_sel", MXC_CCM_CSCMR2, 9, 1, -				mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel));  	clk[ldb_di1_div_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); -	clk[ldb_di1_div] = imx_clk_divider("ldb_di1_div", "ldb_di1_div_3_5", MXC_CCM_CSCMR2, 11, 1); +	clk[ldb_di1_div] = imx_clk_divider_flags("ldb_di1_div", "ldb_di1_div_3_5", MXC_CCM_CSCMR2, 11, 1, 0); +	clk[ldb_di1_sel] = imx_clk_mux_flags("ldb_di1_sel", MXC_CCM_CSCMR2, 9, 1, +				mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel), CLK_SET_RATE_PARENT);  	clk[di_pll4_podf] = imx_clk_divider("di_pll4_podf", "pll4_sw", MXC_CCM_CDCDR, 16, 3); -	clk[ldb_di0_sel] = imx_clk_mux("ldb_di0_sel", MXC_CCM_CSCMR2, 8, 1, -				mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel));  	clk[ldb_di0_div_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); -	clk[ldb_di0_div] = imx_clk_divider("ldb_di0_div", "ldb_di0_div_3_5", MXC_CCM_CSCMR2, 10, 1); +	clk[ldb_di0_div] = imx_clk_divider_flags("ldb_di0_div", "ldb_di0_div_3_5", MXC_CCM_CSCMR2, 10, 1, 0); +	clk[ldb_di0_sel] = imx_clk_mux_flags("ldb_di0_sel", MXC_CCM_CSCMR2, 8, 1, +				mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel), CLK_SET_RATE_PARENT);  	clk[ldb_di0_gate] = imx_clk_gate2("ldb_di0_gate", "ldb_di0_div", MXC_CCM_CCGR6, 28);  	clk[ldb_di1_gate] = imx_clk_gate2("ldb_di1_gate", "ldb_di1_div", MXC_CCM_CCGR6, 30);  	clk[ipu_di0_sel] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,  				mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel));  	clk[ipu_di1_sel] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,  				mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel)); -	clk[tve_ext_sel] = imx_clk_mux("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, -				mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel)); +	clk[tve_ext_sel] = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, +				mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel), CLK_SET_RATE_PARENT);  	clk[tve_gate] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30);  	clk[tve_pred] = imx_clk_divider("tve_pred", "tve_ext_sel", MXC_CCM_CDCDR, 28, 3);  	clk[esdhc1_per_gate] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); @@ -453,6 +486,16 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,  	clk[can2_ipg_gate] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 6);  	clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22); +	clk[cko1_sel] = imx_clk_mux("cko1_sel", MXC_CCM_CCOSR, 0, 4, +				mx53_cko1_sel, ARRAY_SIZE(mx53_cko1_sel)); +	clk[cko1_podf] = imx_clk_divider("cko1_podf", "cko1_sel", MXC_CCM_CCOSR, 4, 3); +	clk[cko1] = imx_clk_gate2("cko1", "cko1_podf", MXC_CCM_CCOSR, 7); + +	clk[cko2_sel] = imx_clk_mux("cko2_sel", MXC_CCM_CCOSR, 16, 5, +				mx53_cko2_sel, ARRAY_SIZE(mx53_cko2_sel)); +	clk[cko2_podf] = imx_clk_divider("cko2_podf", "cko2_sel", MXC_CCM_CCOSR, 21, 3); +	clk[cko2] = imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24); +  	for (i = 0; i < ARRAY_SIZE(clk); i++)  		if (IS_ERR(clk[i]))  			pr_err("i.MX53 clk %d: register failed with %ld\n", diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index d38e54f5b6d..15125900308 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -1,5 +1,5 @@  /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2013 Freescale Semiconductor, Inc.   * Copyright 2011 Linaro Ltd.   *   * The code contained herein is licensed under the GNU General Public @@ -14,6 +14,7 @@  #include <linux/types.h>  #include <linux/clk.h>  #include <linux/clkdev.h> +#include <linux/delay.h>  #include <linux/err.h>  #include <linux/io.h>  #include <linux/of.h> @@ -22,6 +23,12 @@  #include "clk.h"  #include "common.h" +#include "hardware.h" + +#define CCR				0x0 +#define BM_CCR_WB_COUNT			(0x7 << 16) +#define BM_CCR_RBC_BYPASS_COUNT		(0x3f << 21) +#define BM_CCR_RBC_EN			(0x1 << 27)  #define CCGR0				0x68  #define CCGR1				0x6c @@ -67,6 +74,67 @@ void imx6q_set_chicken_bit(void)  	writel_relaxed(val, ccm_base + CGPR);  } +static void imx6q_enable_rbc(bool enable) +{ +	u32 val; +	static bool last_rbc_mode; + +	if (last_rbc_mode == enable) +		return; +	/* +	 * need to mask all interrupts in GPC before +	 * operating RBC configurations +	 */ +	imx_gpc_mask_all(); + +	/* configure RBC enable bit */ +	val = readl_relaxed(ccm_base + CCR); +	val &= ~BM_CCR_RBC_EN; +	val |= enable ? BM_CCR_RBC_EN : 0; +	writel_relaxed(val, ccm_base + CCR); + +	/* configure RBC count */ +	val = readl_relaxed(ccm_base + CCR); +	val &= ~BM_CCR_RBC_BYPASS_COUNT; +	val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0; +	writel(val, ccm_base + CCR); + +	/* +	 * need to delay at least 2 cycles of CKIL(32K) +	 * due to hardware design requirement, which is +	 * ~61us, here we use 65us for safe +	 */ +	udelay(65); + +	/* restore GPC interrupt mask settings */ +	imx_gpc_restore_all(); + +	last_rbc_mode = enable; +} + +static void imx6q_enable_wb(bool enable) +{ +	u32 val; +	static bool last_wb_mode; + +	if (last_wb_mode == enable) +		return; + +	/* configure well bias enable bit */ +	val = readl_relaxed(ccm_base + CLPCR); +	val &= ~BM_CLPCR_WB_PER_AT_LPM; +	val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0; +	writel_relaxed(val, ccm_base + CLPCR); + +	/* configure well bias count */ +	val = readl_relaxed(ccm_base + CCR); +	val &= ~BM_CCR_WB_COUNT; +	val |= enable ? BM_CCR_WB_COUNT : 0; +	writel_relaxed(val, ccm_base + CCR); + +	last_wb_mode = enable; +} +  int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)  {  	u32 val = readl_relaxed(ccm_base + CLPCR); @@ -74,6 +142,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)  	val &= ~BM_CLPCR_LPM;  	switch (mode) {  	case WAIT_CLOCKED: +		imx6q_enable_wb(false); +		imx6q_enable_rbc(false);  		break;  	case WAIT_UNCLOCKED:  		val |= 0x1 << BP_CLPCR_LPM; @@ -92,6 +162,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)  		val |= 0x3 << BP_CLPCR_STBY_COUNT;  		val |= BM_CLPCR_VSTBY;  		val |= BM_CLPCR_SBYOS; +		imx6q_enable_wb(true); +		imx6q_enable_rbc(true);  		break;  	default:  		return -EINVAL; @@ -109,29 +181,29 @@ static const char *periph_clk2_sels[]	= { "pll3_usb_otg", "osc", };  static const char *periph_sels[]	= { "periph_pre", "periph_clk2", };  static const char *periph2_sels[]	= { "periph2_pre", "periph2_clk2", };  static const char *axi_sels[]		= { "periph", "pll2_pfd2_396m", "pll3_pfd1_540m", }; -static const char *audio_sels[]	= { "pll4_audio", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; +static const char *audio_sels[]	= { "pll4_post_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", };  static const char *gpu_axi_sels[]	= { "axi", "ahb", };  static const char *gpu2d_core_sels[]	= { "axi", "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", };  static const char *gpu3d_core_sels[]	= { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd2_396m", };  static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd9_720m", };  static const char *ipu_sels[]		= { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };  static const char *ldb_di_sels[]	= { "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", }; -static const char *ipu_di_pre_sels[]	= { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *ipu_di_pre_sels[]	= { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", };  static const char *ipu1_di0_sels[]	= { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };  static const char *ipu1_di1_sels[]	= { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };  static const char *ipu2_di0_sels[]	= { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };  static const char *ipu2_di1_sels[]	= { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };  static const char *hsi_tx_sels[]	= { "pll3_120m", "pll2_pfd2_396m", };  static const char *pcie_axi_sels[]	= { "axi", "ahb", }; -static const char *ssi_sels[]		= { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio", }; +static const char *ssi_sels[]		= { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_post_div", };  static const char *usdhc_sels[]	= { "pll2_pfd2_396m", "pll2_pfd0_352m", };  static const char *enfc_sels[]	= { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", };  static const char *emi_sels[]		= { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", };  static const char *vdo_axi_sels[]	= { "axi", "ahb", };  static const char *vpu_axi_sels[]	= { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m", }; -static const char *cko1_sels[]	= { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video", +static const char *cko1_sels[]	= { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div",  				    "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", -				    "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio", }; +				    "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_post_div", };  enum mx6q_clks {  	dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, @@ -165,7 +237,7 @@ enum mx6q_clks {  	pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg,  	ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5,  	sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate, -	usbphy2_gate, clk_max +	usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, clk_max  };  static struct clk *clk[clk_max]; @@ -182,6 +254,21 @@ static struct clk_div_table clk_enet_ref_table[] = {  	{ .val = 3, .div = 4, },  }; +static struct clk_div_table post_div_table[] = { +	{ .val = 2, .div = 1, }, +	{ .val = 1, .div = 2, }, +	{ .val = 0, .div = 4, }, +	{ } +}; + +static struct clk_div_table video_div_table[] = { +	{ .val = 0, .div = 1, }, +	{ .val = 1, .div = 2, }, +	{ .val = 2, .div = 1, }, +	{ .val = 3, .div = 4, }, +	{ } +}; +  int __init mx6q_clocks_init(void)  {  	struct device_node *np; @@ -208,6 +295,14 @@ int __init mx6q_clocks_init(void)  	base = of_iomap(np, 0);  	WARN_ON(!base); +	/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ +	if (cpu_is_imx6q() && imx6q_revision() == IMX_CHIP_REVISION_1_0) { +		post_div_table[1].div = 1; +		post_div_table[2].div = 1; +		video_div_table[1].div = 1; +		video_div_table[2].div = 1; +	}; +  	/*                   type                               name         parent_name  base     div_mask */  	clk[pll1_sys]      = imx_clk_pllv3(IMX_PLLV3_SYS,	"pll1_sys",	"osc", base,        0x7f);  	clk[pll2_bus]      = imx_clk_pllv3(IMX_PLLV3_GENERIC,	"pll2_bus",	"osc", base + 0x30, 0x1); @@ -260,6 +355,10 @@ int __init mx6q_clocks_init(void)  	clk[pll3_60m]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);  	clk[twd]       = imx_clk_fixed_factor("twd",       "arm",            1, 2); +	clk[pll4_post_div] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); +	clk[pll5_post_div] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); +	clk[pll5_video_div] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); +  	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm");  	base = of_iomap(np, 0);  	WARN_ON(!base); @@ -283,8 +382,8 @@ int __init mx6q_clocks_init(void)  	clk[gpu3d_shader_sel] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));  	clk[ipu1_sel]         = imx_clk_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));  	clk[ipu2_sel]         = imx_clk_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels)); -	clk[ldb_di0_sel]      = imx_clk_mux("ldb_di0_sel",      base + 0x2c, 9,  3, ldb_di_sels,       ARRAY_SIZE(ldb_di_sels)); -	clk[ldb_di1_sel]      = imx_clk_mux("ldb_di1_sel",      base + 0x2c, 12, 3, ldb_di_sels,       ARRAY_SIZE(ldb_di_sels)); +	clk[ldb_di0_sel]      = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); +	clk[ldb_di1_sel]      = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);  	clk[ipu1_di0_pre_sel] = imx_clk_mux("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels));  	clk[ipu1_di1_pre_sel] = imx_clk_mux("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels));  	clk[ipu2_di0_pre_sel] = imx_clk_mux("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels)); @@ -332,9 +431,9 @@ int __init mx6q_clocks_init(void)  	clk[ipu1_podf]        = imx_clk_divider("ipu1_podf",        "ipu1_sel",          base + 0x3c, 11, 3);  	clk[ipu2_podf]        = imx_clk_divider("ipu2_podf",        "ipu2_sel",          base + 0x3c, 16, 3);  	clk[ldb_di0_div_3_5]  = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); -	clk[ldb_di0_podf]     = imx_clk_divider("ldb_di0_podf",     "ldb_di0_div_3_5",       base + 0x20, 10, 1); +	clk[ldb_di0_podf]     = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);  	clk[ldb_di1_div_3_5]  = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); -	clk[ldb_di1_podf]     = imx_clk_divider("ldb_di1_podf",     "ldb_di1_div_3_5",   base + 0x20, 11, 1); +	clk[ldb_di1_podf]     = imx_clk_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);  	clk[ipu1_di0_pre]     = imx_clk_divider("ipu1_di0_pre",     "ipu1_di0_pre_sel",  base + 0x34, 3,  3);  	clk[ipu1_di1_pre]     = imx_clk_divider("ipu1_di1_pre",     "ipu1_di1_pre_sel",  base + 0x34, 12, 3);  	clk[ipu2_di0_pre]     = imx_clk_divider("ipu2_di0_pre",     "ipu2_di0_pre_sel",  base + 0x38, 3,  3); @@ -448,6 +547,11 @@ int __init mx6q_clocks_init(void)  	clk_register_clkdev(clk[cko1], "cko1", NULL);  	clk_register_clkdev(clk[arm], NULL, "cpu0"); +	if (imx6q_revision() != IMX_CHIP_REVISION_1_0) { +		clk_set_parent(clk[ldb_di0_sel], clk[pll5_video_div]); +		clk_set_parent(clk[ldb_di1_sel], clk[pll5_video_div]); +	} +  	/*  	 * The gpmi needs 100MHz frequency in the EDO/Sync mode,  	 * We can not get the 100MHz from the pll2_pfd0_352m. diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 9d1f3b99d1d..d9d9d9c66df 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -59,6 +59,14 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent,  			reg, shift, width, 0, &imx_ccm_lock);  } +static inline struct clk *imx_clk_divider_flags(const char *name, +		const char *parent, void __iomem *reg, u8 shift, u8 width, +		unsigned long flags) +{ +	return clk_register_divider(NULL, name, parent, flags, +			reg, shift, width, 0, &imx_ccm_lock); +} +  static inline struct clk *imx_clk_gate(const char *name, const char *parent,  		void __iomem *reg, u8 shift)  { @@ -73,6 +81,15 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,  			width, 0, &imx_ccm_lock);  } +static inline struct clk *imx_clk_mux_flags(const char *name, +		void __iomem *reg, u8 shift, u8 width, const char **parents, +		int num_parents, unsigned long flags) +{ +	return clk_register_mux(NULL, name, parents, num_parents, +			flags, reg, shift, width, 0, +			&imx_ccm_lock); +} +  static inline struct clk *imx_clk_fixed_factor(const char *name,  		const char *parent, unsigned int mult, unsigned int div)  { diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 9fea2522d7a..4cba7dbb079 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -1,5 +1,5 @@  /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.   */  /* @@ -74,6 +74,7 @@ extern void mxc_set_cpu_type(unsigned int type);  extern void mxc_restart(char, const char *);  extern void mxc_arch_reset_init(void __iomem *);  extern int mx53_revision(void); +extern int imx6q_revision(void);  extern int mx53_display_revision(void);  extern void imx_set_aips(void __iomem *);  extern int mxc_device_init(void); @@ -128,6 +129,13 @@ extern void imx_src_prepare_restart(void);  extern void imx_gpc_init(void);  extern void imx_gpc_pre_suspend(void);  extern void imx_gpc_post_resume(void); +extern void imx_gpc_mask_all(void); +extern void imx_gpc_restore_all(void); +extern void imx_anatop_init(void); +extern void imx_anatop_pre_suspend(void); +extern void imx_anatop_post_resume(void); +extern void imx_anatop_usb_chrg_detect_disable(void); +extern u32 imx_anatop_get_digprog(void);  extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);  extern void imx6q_set_chicken_bit(void); diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 02b61cdf39b..44a65e9ff1f 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -1,5 +1,5 @@  /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2013 Freescale Semiconductor, Inc.   * Copyright 2011 Linaro Ltd.   *   * The code contained herein is licensed under the GNU General Public @@ -69,6 +69,27 @@ static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)  	return 0;  } +void imx_gpc_mask_all(void) +{ +	void __iomem *reg_imr1 = gpc_base + GPC_IMR1; +	int i; + +	for (i = 0; i < IMR_NUM; i++) { +		gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); +		writel_relaxed(~0, reg_imr1 + i * 4); +	} + +} + +void imx_gpc_restore_all(void) +{ +	void __iomem *reg_imr1 = gpc_base + GPC_IMR1; +	int i; + +	for (i = 0; i < IMR_NUM; i++) +		writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); +} +  static void imx_gpc_irq_unmask(struct irq_data *d)  {  	void __iomem *reg; diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 99502eeefdf..5536fd81379 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -1,5 +1,5 @@  /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2013 Freescale Semiconductor, Inc.   * Copyright 2011 Linaro Ltd.   *   * The code contained herein is licensed under the GNU General Public @@ -38,38 +38,32 @@  #include "cpuidle.h"  #include "hardware.h" -#define IMX6Q_ANALOG_DIGPROG	0x260 +static u32 chip_revision; -static int imx6q_revision(void) +int imx6q_revision(void)  { -	struct device_node *np; -	void __iomem *base; -	static u32 rev; +	return chip_revision; +} -	if (!rev) { -		np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); -		if (!np) -			return IMX_CHIP_REVISION_UNKNOWN; -		base = of_iomap(np, 0); -		if (!base) { -			of_node_put(np); -			return IMX_CHIP_REVISION_UNKNOWN; -		} -		rev =  readl_relaxed(base + IMX6Q_ANALOG_DIGPROG); -		iounmap(base); -		of_node_put(np); -	} +static void __init imx6q_init_revision(void) +{ +	u32 rev = imx_anatop_get_digprog();  	switch (rev & 0xff) {  	case 0: -		return IMX_CHIP_REVISION_1_0; +		chip_revision = IMX_CHIP_REVISION_1_0; +		break;  	case 1: -		return IMX_CHIP_REVISION_1_1; +		chip_revision = IMX_CHIP_REVISION_1_1; +		break;  	case 2: -		return IMX_CHIP_REVISION_1_2; +		chip_revision = IMX_CHIP_REVISION_1_2; +		break;  	default: -		return IMX_CHIP_REVISION_UNKNOWN; +		chip_revision = IMX_CHIP_REVISION_UNKNOWN;  	} + +	mxc_set_cpu_type(rev >> 16 & 0xff);  }  static void imx6q_restart(char mode, const char *cmd) @@ -164,29 +158,7 @@ static void __init imx6q_1588_init(void)  }  static void __init imx6q_usb_init(void)  { -	struct regmap *anatop; - -#define HW_ANADIG_USB1_CHRG_DETECT		0x000001b0 -#define HW_ANADIG_USB2_CHRG_DETECT		0x00000210 - -#define BM_ANADIG_USB_CHRG_DETECT_EN_B		0x00100000 -#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B	0x00080000 - -	anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop"); -	if (!IS_ERR(anatop)) { -		/* -		 * The external charger detector needs to be disabled, -		 * or the signal at DP will be poor -		 */ -		regmap_write(anatop, HW_ANADIG_USB1_CHRG_DETECT, -				BM_ANADIG_USB_CHRG_DETECT_EN_B -				| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); -		regmap_write(anatop, HW_ANADIG_USB2_CHRG_DETECT, -				BM_ANADIG_USB_CHRG_DETECT_EN_B | -				BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); -	} else { -		pr_warn("failed to find fsl,imx6q-anatop regmap\n"); -	} +	imx_anatop_usb_chrg_detect_disable();  }  static void __init imx6q_init_machine(void) @@ -196,6 +168,7 @@ static void __init imx6q_init_machine(void)  	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +	imx_anatop_init();  	imx6q_pm_init();  	imx6q_usb_init();  	imx6q_1588_init(); @@ -282,6 +255,7 @@ static void __init imx6q_map_io(void)  static void __init imx6q_init_irq(void)  { +	imx6q_init_revision();  	l2x0_of_init(0, ~0UL);  	imx_src_init();  	imx_gpc_init(); @@ -292,15 +266,17 @@ static void __init imx6q_timer_init(void)  {  	mx6q_clocks_init();  	clocksource_of_init(); -	imx_print_silicon_rev("i.MX6Q", imx6q_revision()); +	imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", +			      imx6q_revision());  }  static const char *imx6q_dt_compat[] __initdata = { +	"fsl,imx6dl",  	"fsl,imx6q",  	NULL,  }; -DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)") +DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")  	.smp		= smp_ops(imx_smp_ops),  	.map_io		= imx6q_map_io,  	.init_irq	= imx6q_init_irq, diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c index 7a146671e65..3c609c52d3e 100644 --- a/arch/arm/mach-imx/mm-imx1.c +++ b/arch/arm/mach-imx/mm-imx1.c @@ -51,6 +51,8 @@ void __init mx1_init_irq(void)  void __init imx1_soc_init(void)  { +	mxc_device_init(); +  	mxc_register_gpio("imx1-gpio", 0, MX1_GPIO1_BASE_ADDR, SZ_256,  						MX1_GPIO_INT_PORTA, 0);  	mxc_register_gpio("imx1-gpio", 1, MX1_GPIO2_BASE_ADDR, SZ_256, diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 7dce17a9fe6..8629e5be7ec 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -34,6 +34,8 @@  #define MXC_CPU_MX35		35  #define MXC_CPU_MX51		51  #define MXC_CPU_MX53		53 +#define MXC_CPU_IMX6DL		0x61 +#define MXC_CPU_IMX6Q		0x63  #define IMX_CHIP_REVISION_1_0		0x10  #define IMX_CHIP_REVISION_1_1		0x11 @@ -150,6 +152,15 @@ extern unsigned int __mxc_cpu_type;  #endif  #ifndef __ASSEMBLY__ +static inline bool cpu_is_imx6dl(void) +{ +	return __mxc_cpu_type == MXC_CPU_IMX6DL; +} + +static inline bool cpu_is_imx6q(void) +{ +	return __mxc_cpu_type == MXC_CPU_IMX6Q; +}  struct cpu_op {  	u32 cpu_rate; diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 77e9a25ed0f..4a69305db65 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -68,8 +68,8 @@ static void __init imx_smp_init_cpus(void)  	ncores = scu_get_core_count(scu_base); -	for (i = 0; i < ncores; i++) -		set_cpu_possible(i, true); +	for (i = ncores; i < NR_CPUS; i++) +		set_cpu_possible(i, false);  }  void imx_smp_prepare(void) diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index 5faba7a3c95..204942749e2 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -1,5 +1,5 @@  /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2013 Freescale Semiconductor, Inc.   * Copyright 2011 Linaro Ltd.   *   * The code contained herein is licensed under the GNU General Public @@ -34,10 +34,12 @@ static int imx6q_pm_enter(suspend_state_t state)  	case PM_SUSPEND_MEM:  		imx6q_set_lpm(STOP_POWER_OFF);  		imx_gpc_pre_suspend(); +		imx_anatop_pre_suspend();  		imx_set_cpu_jump(0, v7_cpu_resume);  		/* Zzz ... */  		cpu_suspend(0, imx6q_suspend_finish);  		imx_smp_prepare(); +		imx_anatop_post_resume();  		imx_gpc_post_resume();  		imx6q_set_lpm(WAIT_CLOCKED);  		break; diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index 97d08688948..10a6b1a8c5a 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -14,6 +14,7 @@  #include <linux/io.h>  #include <linux/of.h>  #include <linux/of_address.h> +#include <linux/reset-controller.h>  #include <linux/smp.h>  #include <asm/smp_plat.h>  #include "common.h" @@ -21,10 +22,65 @@  #define SRC_SCR				0x000  #define SRC_GPR1			0x020  #define BP_SRC_SCR_WARM_RESET_ENABLE	0 +#define BP_SRC_SCR_SW_GPU_RST		1 +#define BP_SRC_SCR_SW_VPU_RST		2 +#define BP_SRC_SCR_SW_IPU1_RST		3 +#define BP_SRC_SCR_SW_OPEN_VG_RST	4 +#define BP_SRC_SCR_SW_IPU2_RST		12  #define BP_SRC_SCR_CORE1_RST		14  #define BP_SRC_SCR_CORE1_ENABLE		22  static void __iomem *src_base; +static DEFINE_SPINLOCK(scr_lock); + +static const int sw_reset_bits[5] = { +	BP_SRC_SCR_SW_GPU_RST, +	BP_SRC_SCR_SW_VPU_RST, +	BP_SRC_SCR_SW_IPU1_RST, +	BP_SRC_SCR_SW_OPEN_VG_RST, +	BP_SRC_SCR_SW_IPU2_RST +}; + +static int imx_src_reset_module(struct reset_controller_dev *rcdev, +		unsigned long sw_reset_idx) +{ +	unsigned long timeout; +	unsigned long flags; +	int bit; +	u32 val; + +	if (!src_base) +		return -ENODEV; + +	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits)) +		return -EINVAL; + +	bit = 1 << sw_reset_bits[sw_reset_idx]; + +	spin_lock_irqsave(&scr_lock, flags); +	val = readl_relaxed(src_base + SRC_SCR); +	val |= bit; +	writel_relaxed(val, src_base + SRC_SCR); +	spin_unlock_irqrestore(&scr_lock, flags); + +	timeout = jiffies + msecs_to_jiffies(1000); +	while (readl(src_base + SRC_SCR) & bit) { +		if (time_after(jiffies, timeout)) +			return -ETIME; +		cpu_relax(); +	} + +	return 0; +} + +static struct reset_control_ops imx_src_ops = { +	.reset = imx_src_reset_module, +}; + +static struct reset_controller_dev imx_reset_controller = { +	.ops = &imx_src_ops, +	.nr_resets = ARRAY_SIZE(sw_reset_bits), +};  void imx_enable_cpu(int cpu, bool enable)  { @@ -32,9 +88,11 @@ void imx_enable_cpu(int cpu, bool enable)  	cpu = cpu_logical_map(cpu);  	mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); +	spin_lock(&scr_lock);  	val = readl_relaxed(src_base + SRC_SCR);  	val = enable ? val | mask : val & ~mask;  	writel_relaxed(val, src_base + SRC_SCR); +	spin_unlock(&scr_lock);  }  void imx_set_cpu_jump(int cpu, void *jump_addr) @@ -61,9 +119,11 @@ void imx_src_prepare_restart(void)  	u32 val;  	/* clear enable bits of secondary cores */ +	spin_lock(&scr_lock);  	val = readl_relaxed(src_base + SRC_SCR);  	val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE);  	writel_relaxed(val, src_base + SRC_SCR); +	spin_unlock(&scr_lock);  	/* clear persistent entry register of primary core */  	writel_relaxed(0, src_base + SRC_GPR1); @@ -80,11 +140,17 @@ void __init imx_src_init(void)  	src_base = of_iomap(np, 0);  	WARN_ON(!src_base); +	imx_reset_controller.of_node = np; +	if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) +		reset_controller_register(&imx_reset_controller); +  	/*  	 * force warm reset sources to generate cold reset  	 * for a more reliable restart  	 */ +	spin_lock(&scr_lock);  	val = readl_relaxed(src_base + SRC_SCR);  	val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);  	writel_relaxed(val, src_base + SRC_SCR); +	spin_unlock(&scr_lock);  } diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile index cdbca328a41..e1f3735d341 100644 --- a/arch/arm/mach-kirkwood/Makefile +++ b/arch/arm/mach-kirkwood/Makefile @@ -1,4 +1,4 @@ -obj-y				+= common.o addr-map.o irq.o pcie.o mpp.o +obj-y				+= common.o irq.o pcie.o mpp.o  obj-$(CONFIG_MACH_D2NET_V2)		+= d2net_v2-setup.o lacie_v2-common.o  obj-$(CONFIG_MACH_DB88F6281_BP)		+= db88f6281-bp-setup.o diff --git a/arch/arm/mach-kirkwood/addr-map.c b/arch/arm/mach-kirkwood/addr-map.c deleted file mode 100644 index 8f0d162a1e1..00000000000 --- a/arch/arm/mach-kirkwood/addr-map.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * arch/arm/mach-kirkwood/addr-map.c - * - * Address map functions for Marvell Kirkwood SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mbus.h> -#include <linux/io.h> -#include <mach/hardware.h> -#include <plat/addr-map.h> -#include "common.h" - -/* - * Generic Address Decode Windows bit settings - */ -#define TARGET_DEV_BUS		1 -#define TARGET_SRAM		3 -#define TARGET_PCIE		4 -#define ATTR_DEV_SPI_ROM	0x1e -#define ATTR_DEV_BOOT		0x1d -#define ATTR_DEV_NAND		0x2f -#define ATTR_DEV_CS3		0x37 -#define ATTR_DEV_CS2		0x3b -#define ATTR_DEV_CS1		0x3d -#define ATTR_DEV_CS0		0x3e -#define ATTR_PCIE_IO		0xe0 -#define ATTR_PCIE_MEM		0xe8 -#define ATTR_PCIE1_IO		0xd0 -#define ATTR_PCIE1_MEM		0xd8 -#define ATTR_SRAM		0x01 - -/* - * Description of the windows needed by the platform code - */ -static struct __initdata orion_addr_map_cfg addr_map_cfg = { -	.num_wins = 8, -	.remappable_wins = 4, -	.bridge_virt_base = BRIDGE_VIRT_BASE, -}; - -static const struct __initdata orion_addr_map_info addr_map_info[] = { -	/* -	 * Windows for PCIe IO+MEM space. -	 */ -	{ 0, KIRKWOOD_PCIE_IO_PHYS_BASE, KIRKWOOD_PCIE_IO_SIZE, -	  TARGET_PCIE, ATTR_PCIE_IO, KIRKWOOD_PCIE_IO_BUS_BASE -	}, -	{ 1, KIRKWOOD_PCIE_MEM_PHYS_BASE, KIRKWOOD_PCIE_MEM_SIZE, -	  TARGET_PCIE, ATTR_PCIE_MEM, KIRKWOOD_PCIE_MEM_BUS_BASE -	}, -	{ 2, KIRKWOOD_PCIE1_IO_PHYS_BASE, KIRKWOOD_PCIE1_IO_SIZE, -	  TARGET_PCIE, ATTR_PCIE1_IO, KIRKWOOD_PCIE1_IO_BUS_BASE -	}, -	{ 3, KIRKWOOD_PCIE1_MEM_PHYS_BASE, KIRKWOOD_PCIE1_MEM_SIZE, -	  TARGET_PCIE, ATTR_PCIE1_MEM, KIRKWOOD_PCIE1_MEM_BUS_BASE -	}, -	/* -	 * Window for NAND controller. -	 */ -	{ 4, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE, -	  TARGET_DEV_BUS, ATTR_DEV_NAND, -1 -	}, -	/* -	 * Window for SRAM. -	 */ -	{ 5, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE, -	  TARGET_SRAM, ATTR_SRAM, -1 -	}, -	/* End marker */ -	{ -1, 0, 0, 0, 0, 0 } -}; - -void __init kirkwood_setup_cpu_mbus(void) -{ -	/* -	 * Disable, clear and configure windows. -	 */ -	orion_config_wins(&addr_map_cfg, addr_map_info); - -	/* -	 * Setup MBUS dram target info. -	 */ -	orion_setup_cpu_mbus_target(&addr_map_cfg, -				    (void __iomem *) DDR_WINDOW_CPU_BASE); -} diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c index 7904758e771..e9647b80cb5 100644 --- a/arch/arm/mach-kirkwood/board-dt.c +++ b/arch/arm/mach-kirkwood/board-dt.c @@ -93,7 +93,7 @@ static void __init kirkwood_dt_init(void)  	 */  	writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG); -	kirkwood_setup_cpu_mbus(); +	kirkwood_setup_wins();  	kirkwood_l2_init(); diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index 49792a0cd2d..c2cae69e6d2 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -33,7 +33,6 @@  #include <linux/platform_data/usb-ehci-orion.h>  #include <plat/common.h>  #include <plat/time.h> -#include <plat/addr-map.h>  #include <linux/platform_data/dma-mv_xor.h>  #include "common.h" @@ -535,6 +534,9 @@ void __init kirkwood_init_early(void)  	 * the allocations won't fail.  	 */  	init_dma_coherent_pool_size(SZ_1M); +	mvebu_mbus_init("marvell,kirkwood-mbus", +			BRIDGE_WINS_BASE, BRIDGE_WINS_SZ, +			DDR_WINDOW_CPU_BASE, DDR_WINDOW_CPU_SZ);  }  int kirkwood_tclk; @@ -650,6 +652,38 @@ char * __init kirkwood_id(void)  	}  } +void __init kirkwood_setup_wins(void) +{ +	/* +	 * The PCIe windows will no longer be statically allocated +	 * here once Kirkwood is migrated to the pci-mvebu driver. +	 */ +	mvebu_mbus_add_window_remap_flags("pcie0.0", +					  KIRKWOOD_PCIE_IO_PHYS_BASE, +					  KIRKWOOD_PCIE_IO_SIZE, +					  KIRKWOOD_PCIE_IO_BUS_BASE, +					  MVEBU_MBUS_PCI_IO); +	mvebu_mbus_add_window_remap_flags("pcie0.0", +					  KIRKWOOD_PCIE_MEM_PHYS_BASE, +					  KIRKWOOD_PCIE_MEM_SIZE, +					  MVEBU_MBUS_NO_REMAP, +					  MVEBU_MBUS_PCI_MEM); +	mvebu_mbus_add_window_remap_flags("pcie1.0", +					  KIRKWOOD_PCIE1_IO_PHYS_BASE, +					  KIRKWOOD_PCIE1_IO_SIZE, +					  KIRKWOOD_PCIE1_IO_BUS_BASE, +					  MVEBU_MBUS_PCI_IO); +	mvebu_mbus_add_window_remap_flags("pcie1.0", +					  KIRKWOOD_PCIE1_MEM_PHYS_BASE, +					  KIRKWOOD_PCIE1_MEM_SIZE, +					  MVEBU_MBUS_NO_REMAP, +					  MVEBU_MBUS_PCI_MEM); +	mvebu_mbus_add_window("nand", KIRKWOOD_NAND_MEM_PHYS_BASE, +			      KIRKWOOD_NAND_MEM_SIZE); +	mvebu_mbus_add_window("sram", KIRKWOOD_SRAM_PHYS_BASE, +			      KIRKWOOD_SRAM_SIZE); +} +  void __init kirkwood_l2_init(void)  {  #ifdef CONFIG_CACHE_FEROCEON_L2 @@ -675,7 +709,7 @@ void __init kirkwood_init(void)  	 */  	writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG); -	kirkwood_setup_cpu_mbus(); +	kirkwood_setup_wins();  	kirkwood_l2_init(); diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h index 3147be2f34d..21da3b1ebd7 100644 --- a/arch/arm/mach-kirkwood/common.h +++ b/arch/arm/mach-kirkwood/common.h @@ -30,7 +30,7 @@ void kirkwood_init(void);  void kirkwood_init_early(void);  void kirkwood_init_irq(void); -void kirkwood_setup_cpu_mbus(void); +void kirkwood_setup_wins(void);  void kirkwood_enable_pcie(void);  void kirkwood_pcie_id(u32 *dev, u32 *rev); diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h index a05563a31c9..92976cef391 100644 --- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h +++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h @@ -60,8 +60,9 @@   * Register Map   */  #define DDR_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE + 0x00000) -#define DDR_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE + 0x00000) -#define  DDR_WINDOW_CPU_BASE	(DDR_VIRT_BASE + 0x1500) +#define DDR_PHYS_BASE           (KIRKWOOD_REGS_PHYS_BASE + 0x00000) +#define  DDR_WINDOW_CPU_BASE    (DDR_PHYS_BASE + 0x1500) +#define  DDR_WINDOW_CPU_SZ      (0x20)  #define DDR_OPERATION_BASE	(DDR_PHYS_BASE + 0x1418)  #define DEV_BUS_PHYS_BASE	(KIRKWOOD_REGS_PHYS_BASE + 0x10000) @@ -80,6 +81,8 @@  #define BRIDGE_VIRT_BASE	(KIRKWOOD_REGS_VIRT_BASE + 0x20000)  #define BRIDGE_PHYS_BASE	(KIRKWOOD_REGS_PHYS_BASE + 0x20000) +#define  BRIDGE_WINS_BASE       (BRIDGE_PHYS_BASE) +#define  BRIDGE_WINS_SZ         (0x80)  #define CRYPTO_PHYS_BASE	(KIRKWOOD_REGS_PHYS_BASE + 0x30000) diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index d96ad4c0997..7f43e6c2f8c 100644 --- a/arch/arm/mach-kirkwood/pcie.c +++ b/arch/arm/mach-kirkwood/pcie.c @@ -17,7 +17,6 @@  #include <asm/mach/pci.h>  #include <plat/pcie.h>  #include <mach/bridge-regs.h> -#include <plat/addr-map.h>  #include "common.h"  static void kirkwood_enable_pcie_clk(const char *port) diff --git a/arch/arm/mach-mv78xx0/Makefile b/arch/arm/mach-mv78xx0/Makefile index 67a13f9bfe6..7cd04634d30 100644 --- a/arch/arm/mach-mv78xx0/Makefile +++ b/arch/arm/mach-mv78xx0/Makefile @@ -1,4 +1,4 @@ -obj-y				+= common.o addr-map.o mpp.o irq.o pcie.o +obj-y				+= common.o mpp.o irq.o pcie.o  obj-$(CONFIG_MACH_DB78X00_BP)	+= db78x00-bp-setup.o  obj-$(CONFIG_MACH_RD78X00_MASA)	+= rd78x00-masa-setup.o  obj-$(CONFIG_MACH_TERASTATION_WXL) += buffalo-wxl-setup.o diff --git a/arch/arm/mach-mv78xx0/addr-map.c b/arch/arm/mach-mv78xx0/addr-map.c deleted file mode 100644 index 26e9876b50e..00000000000 --- a/arch/arm/mach-mv78xx0/addr-map.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * arch/arm/mach-mv78xx0/addr-map.c - * - * Address map functions for Marvell MV78xx0 SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mbus.h> -#include <linux/io.h> -#include <plat/addr-map.h> -#include <mach/mv78xx0.h> -#include "common.h" - -/* - * Generic Address Decode Windows bit settings - */ -#define TARGET_DEV_BUS		1 -#define TARGET_PCIE0		4 -#define TARGET_PCIE1		8 -#define TARGET_PCIE(i)		((i) ? TARGET_PCIE1 : TARGET_PCIE0) -#define ATTR_DEV_SPI_ROM	0x1f -#define ATTR_DEV_BOOT		0x2f -#define ATTR_DEV_CS3		0x37 -#define ATTR_DEV_CS2		0x3b -#define ATTR_DEV_CS1		0x3d -#define ATTR_DEV_CS0		0x3e -#define ATTR_PCIE_IO(l)		(0xf0 & ~(0x10 << (l))) -#define ATTR_PCIE_MEM(l)	(0xf8 & ~(0x10 << (l))) - -/* - * CPU Address Decode Windows registers - */ -#define WIN0_OFF(n)		(BRIDGE_VIRT_BASE + 0x0000 + ((n) << 4)) -#define WIN8_OFF(n)		(BRIDGE_VIRT_BASE + 0x0900 + (((n) - 8) << 4)) - -static void __init __iomem *win_cfg_base(const struct orion_addr_map_cfg *cfg, int win) -{ -	/* -	 * Find the control register base address for this window. -	 * -	 * BRIDGE_VIRT_BASE points to the right (CPU0's or CPU1's) -	 * MBUS bridge depending on which CPU core we're running on, -	 * so we don't need to take that into account here. -	 */ - -	return (win < 8) ? WIN0_OFF(win) : WIN8_OFF(win); -} - -/* - * Description of the windows needed by the platform code - */ -static struct orion_addr_map_cfg addr_map_cfg __initdata = { -	.num_wins = 14, -	.remappable_wins = 8, -	.win_cfg_base = win_cfg_base, -}; - -void __init mv78xx0_setup_cpu_mbus(void) -{ -	/* -	 * Disable, clear and configure windows. -	 */ -	orion_config_wins(&addr_map_cfg, NULL); - -	/* -	 * Setup MBUS dram target info. -	 */ -	if (mv78xx0_core_index() == 0) -		orion_setup_cpu_mbus_target(&addr_map_cfg, -					    (void __iomem *) DDR_WINDOW_CPU0_BASE); -	else -		orion_setup_cpu_mbus_target(&addr_map_cfg, -					    (void __iomem *) DDR_WINDOW_CPU1_BASE); -} - -void __init mv78xx0_setup_pcie_io_win(int window, u32 base, u32 size, -				      int maj, int min) -{ -	orion_setup_cpu_win(&addr_map_cfg, window, base, size, -			    TARGET_PCIE(maj), ATTR_PCIE_IO(min), 0); -} - -void __init mv78xx0_setup_pcie_mem_win(int window, u32 base, u32 size, -				       int maj, int min) -{ -	orion_setup_cpu_win(&addr_map_cfg, window, base, size, -			    TARGET_PCIE(maj), ATTR_PCIE_MEM(min), -1); -} diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index 0efa14498eb..749a7f8c499 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -334,6 +334,14 @@ void __init mv78xx0_uart3_init(void)  void __init mv78xx0_init_early(void)  {  	orion_time_set_base(TIMER_VIRT_BASE); +	if (mv78xx0_core_index() == 0) +		mvebu_mbus_init("marvell,mv78xx0-mbus", +				BRIDGE_WINS_CPU0_BASE, BRIDGE_WINS_SZ, +				DDR_WINDOW_CPU0_BASE, DDR_WINDOW_CPU_SZ); +	else +		mvebu_mbus_init("marvell,mv78xx0-mbus", +				BRIDGE_WINS_CPU1_BASE, BRIDGE_WINS_SZ, +				DDR_WINDOW_CPU1_BASE, DDR_WINDOW_CPU_SZ);  }  void __init_refok mv78xx0_timer_init(void) @@ -397,8 +405,6 @@ void __init mv78xx0_init(void)  	printk("HCLK = %dMHz, ", (hclk + 499999) / 1000000);  	printk("TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000); -	mv78xx0_setup_cpu_mbus(); -  #ifdef CONFIG_CACHE_FEROCEON_L2  	feroceon_l2_init(is_l2_writethrough());  #endif diff --git a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h index 46200a183cf..723748d8ba7 100644 --- a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h +++ b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h @@ -60,13 +60,18 @@   */  #define BRIDGE_VIRT_BASE	(MV78XX0_CORE_REGS_VIRT_BASE)  #define BRIDGE_PHYS_BASE	(MV78XX0_CORE_REGS_PHYS_BASE) +#define  BRIDGE_WINS_CPU0_BASE  (MV78XX0_CORE0_REGS_PHYS_BASE) +#define  BRIDGE_WINS_CPU1_BASE  (MV78XX0_CORE1_REGS_PHYS_BASE) +#define  BRIDGE_WINS_SZ         (0xA000)  /*   * Register Map   */  #define DDR_VIRT_BASE		(MV78XX0_REGS_VIRT_BASE + 0x00000) -#define  DDR_WINDOW_CPU0_BASE	(DDR_VIRT_BASE + 0x1500) -#define  DDR_WINDOW_CPU1_BASE	(DDR_VIRT_BASE + 0x1570) +#define DDR_PHYS_BASE           (MV78XX0_REGS_PHYS_BASE + 0x00000) +#define  DDR_WINDOW_CPU0_BASE	(DDR_PHYS_BASE + 0x1500) +#define  DDR_WINDOW_CPU1_BASE	(DDR_PHYS_BASE + 0x1570) +#define  DDR_WINDOW_CPU_SZ      (0x20)  #define DEV_BUS_PHYS_BASE	(MV78XX0_REGS_PHYS_BASE + 0x10000)  #define DEV_BUS_VIRT_BASE	(MV78XX0_REGS_VIRT_BASE + 0x10000) diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c index ee8c0b51df2..dc26a654c49 100644 --- a/arch/arm/mach-mv78xx0/pcie.c +++ b/arch/arm/mach-mv78xx0/pcie.c @@ -10,11 +10,11 @@  #include <linux/kernel.h>  #include <linux/pci.h> +#include <linux/mbus.h>  #include <video/vga.h>  #include <asm/irq.h>  #include <asm/mach/pci.h>  #include <plat/pcie.h> -#include <plat/addr-map.h>  #include <mach/mv78xx0.h>  #include "common.h" @@ -54,7 +54,6 @@ static void __init mv78xx0_pcie_preinit(void)  	int i;  	u32 size_each;  	u32 start; -	int win = 0;  	pcie_io_space.name = "PCIe I/O Space";  	pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0); @@ -72,6 +71,7 @@ static void __init mv78xx0_pcie_preinit(void)  	start = MV78XX0_PCIE_MEM_PHYS_BASE;  	for (i = 0; i < num_pcie_ports; i++) {  		struct pcie_port *pp = pcie_port + i; +		char winname[MVEBU_MBUS_MAX_WINNAME_SZ];  		snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),  			"PCIe %d.%d MEM", pp->maj, pp->min); @@ -85,12 +85,17 @@ static void __init mv78xx0_pcie_preinit(void)  		if (request_resource(&iomem_resource, &pp->res))  			panic("can't allocate PCIe MEM sub-space"); -		mv78xx0_setup_pcie_mem_win(win + i + 8, pp->res.start, -					   resource_size(&pp->res), -					   pp->maj, pp->min); +		snprintf(winname, sizeof(winname), "pcie%d.%d", +			 pp->maj, pp->min); -		mv78xx0_setup_pcie_io_win(win + i, i * SZ_64K, SZ_64K, -					  pp->maj, pp->min); +		mvebu_mbus_add_window_remap_flags(winname, +						  pp->res.start, +						  resource_size(&pp->res), +						  MVEBU_MBUS_NO_REMAP, +						  MVEBU_MBUS_PCI_MEM); +		mvebu_mbus_add_window_remap_flags(winname, +						  i * SZ_64K, SZ_64K, +						  0, MVEBU_MBUS_PCI_IO);  	}  } diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 440b13ef1fe..e11acbb0a46 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -13,6 +13,8 @@ config ARCH_MVEBU  	select MVEBU_CLK_CORE  	select MVEBU_CLK_CPU  	select MVEBU_CLK_GATING +	select MVEBU_MBUS +	select ZONE_DMA if ARM_LPAE  if ARCH_MVEBU diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index da93bcbc74c..ba769e082ad 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -5,6 +5,6 @@ AFLAGS_coherency_ll.o		:= -Wa,-march=armv7-a  obj-y				 += system-controller.o  obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o -obj-$(CONFIG_ARCH_MVEBU)	 += addr-map.o coherency.o coherency_ll.o pmsu.o irq-armada-370-xp.o  +obj-$(CONFIG_ARCH_MVEBU)	 += coherency.o coherency_ll.o pmsu.o irq-armada-370-xp.o  obj-$(CONFIG_SMP)                += platsmp.o headsmp.o  obj-$(CONFIG_HOTPLUG_CPU)        += hotplug.o diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c deleted file mode 100644 index ab9b3bd4fef..00000000000 --- a/arch/arm/mach-mvebu/addr-map.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Address map functions for Marvell 370 / XP SoCs - * - * Copyright (C) 2012 Marvell - * - * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mbus.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <plat/addr-map.h> - -/* - * Generic Address Decode Windows bit settings - */ -#define ARMADA_XP_TARGET_DEV_BUS	1 -#define   ARMADA_XP_ATTR_DEV_BOOTROM    0x1D -#define ARMADA_XP_TARGET_ETH1		3 -#define ARMADA_XP_TARGET_PCIE_0_2	4 -#define ARMADA_XP_TARGET_ETH0		7 -#define ARMADA_XP_TARGET_PCIE_1_3	8 - -#define ARMADA_370_TARGET_DEV_BUS       1 -#define   ARMADA_370_ATTR_DEV_BOOTROM   0x1D -#define ARMADA_370_TARGET_PCIE_0        4 -#define ARMADA_370_TARGET_PCIE_1        8 - -#define ARMADA_WINDOW_8_PLUS_OFFSET       0x90 -#define ARMADA_SDRAM_ADDR_DECODING_OFFSET 0x180 - -static const struct __initdata orion_addr_map_info -armada_xp_addr_map_info[] = { -	/* -	 * Window for the BootROM, needed for SMP on Armada XP -	 */ -	{ 0, 0xfff00000, SZ_1M, ARMADA_XP_TARGET_DEV_BUS, -	  ARMADA_XP_ATTR_DEV_BOOTROM, -1 }, -	/* End marker */ -	{ -1, 0, 0, 0, 0, 0 }, -}; - -static const struct __initdata orion_addr_map_info -armada_370_addr_map_info[] = { -	/* End marker */ -	{ -1, 0, 0, 0, 0, 0 }, -}; - -static struct of_device_id of_addr_decoding_controller_table[] = { -	{ .compatible = "marvell,armada-addr-decoding-controller" }, -	{ /* end of list */ }, -}; - -static void __iomem * -armada_cfg_base(const struct orion_addr_map_cfg *cfg, int win) -{ -	unsigned int offset; - -	/* The register layout is a bit annoying and the below code -	 * tries to cope with it. -	 * - At offset 0x0, there are the registers for the first 8 -	 *   windows, with 4 registers of 32 bits per window (ctrl, -	 *   base, remap low, remap high) -	 * - Then at offset 0x80, there is a hole of 0x10 bytes for -	 *   the internal registers base address and internal units -	 *   sync barrier register. -	 * - Then at offset 0x90, there the registers for 12 -	 *   windows, with only 2 registers of 32 bits per window -	 *   (ctrl, base). -	 */ -	if (win < 8) -		offset = (win << 4); -	else -		offset = ARMADA_WINDOW_8_PLUS_OFFSET + ((win - 8) << 3); - -	return cfg->bridge_virt_base + offset; -} - -static struct __initdata orion_addr_map_cfg addr_map_cfg = { -	.num_wins = 20, -	.remappable_wins = 8, -	.win_cfg_base = armada_cfg_base, -}; - -static int __init armada_setup_cpu_mbus(void) -{ -	struct device_node *np; -	void __iomem *mbus_unit_addr_decoding_base; -	void __iomem *sdram_addr_decoding_base; - -	np = of_find_matching_node(NULL, of_addr_decoding_controller_table); -	if (!np) -		return -ENODEV; - -	mbus_unit_addr_decoding_base = of_iomap(np, 0); -	BUG_ON(!mbus_unit_addr_decoding_base); - -	sdram_addr_decoding_base = -		mbus_unit_addr_decoding_base + -		ARMADA_SDRAM_ADDR_DECODING_OFFSET; - -	addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; - -	if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric")) -		addr_map_cfg.hw_io_coherency = 1; - -	/* -	 * Disable, clear and configure windows. -	 */ -	if (of_machine_is_compatible("marvell,armadaxp")) -		orion_config_wins(&addr_map_cfg, armada_xp_addr_map_info); -	else if (of_machine_is_compatible("marvell,armada370")) -		orion_config_wins(&addr_map_cfg, armada_370_addr_map_info); -	else { -		pr_err("Unsupported SoC\n"); -		return -EINVAL; -	} - -	/* -	 * Setup MBUS dram target info. -	 */ -	orion_setup_cpu_mbus_target(&addr_map_cfg, -				    sdram_addr_decoding_base); -	return 0; -} - -/* Using a early_initcall is needed so that this initialization gets - * done before the SMP initialization, which requires the BootROM to - * be remapped. */ -early_initcall(armada_setup_cpu_mbus); diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index a5ea616d6d1..12d3655830d 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c @@ -19,6 +19,7 @@  #include <linux/time-armada-370-xp.h>  #include <linux/clk/mvebu.h>  #include <linux/dma-mapping.h> +#include <linux/mbus.h>  #include <asm/mach/arch.h>  #include <asm/mach/map.h>  #include <asm/mach/time.h> @@ -48,12 +49,29 @@ void __init armada_370_xp_timer_and_clk_init(void)  void __init armada_370_xp_init_early(void)  { +	char *mbus_soc_name; +  	/*  	 * Some Armada 370/XP devices allocate their coherent buffers  	 * from atomic context. Increase size of atomic coherent pool  	 * to make sure such the allocations won't fail.  	 */  	init_dma_coherent_pool_size(SZ_1M); + +	/* +	 * This initialization will be replaced by a DT-based +	 * initialization once the mvebu-mbus driver gains DT support. +	 */ +	if (of_machine_is_compatible("marvell,armada370")) +		mbus_soc_name = "marvell,armada370-mbus"; +	else +		mbus_soc_name = "marvell,armadaxp-mbus"; + +	mvebu_mbus_init(mbus_soc_name, +			ARMADA_370_XP_MBUS_WINS_BASE, +			ARMADA_370_XP_MBUS_WINS_SIZE, +			ARMADA_370_XP_SDRAM_WINS_BASE, +			ARMADA_370_XP_SDRAM_WINS_SIZE);  }  static void __init armada_370_xp_dt_init(void) diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h index c6a7d74fddf..2070e1b4f34 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.h +++ b/arch/arm/mach-mvebu/armada-370-xp.h @@ -16,9 +16,15 @@  #define __MACH_ARMADA_370_XP_H  #define ARMADA_370_XP_REGS_PHYS_BASE	0xd0000000 -#define ARMADA_370_XP_REGS_VIRT_BASE	IOMEM(0xfeb00000) +#define ARMADA_370_XP_REGS_VIRT_BASE	IOMEM(0xfec00000)  #define ARMADA_370_XP_REGS_SIZE		SZ_1M +/* These defines can go away once mvebu-mbus has a DT binding */ +#define ARMADA_370_XP_MBUS_WINS_BASE    (ARMADA_370_XP_REGS_PHYS_BASE + 0x20000) +#define ARMADA_370_XP_MBUS_WINS_SIZE    0x100 +#define ARMADA_370_XP_SDRAM_WINS_BASE   (ARMADA_370_XP_REGS_PHYS_BASE + 0x20180) +#define ARMADA_370_XP_SDRAM_WINS_SIZE   0x20 +  #ifdef CONFIG_SMP  #include <linux/cpumask.h> diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index fe16aaf7c19..875ea748391 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -21,6 +21,7 @@  #include <linux/smp.h>  #include <linux/clk.h>  #include <linux/of.h> +#include <linux/mbus.h>  #include <asm/cacheflush.h>  #include <asm/smp_plat.h>  #include "common.h" @@ -109,6 +110,7 @@ void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)  	set_secondary_cpus_clock();  	flush_cache_all();  	set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); +	mvebu_mbus_add_window("bootrom", 0xfff00000, SZ_1M);  }  struct smp_operations armada_xp_smp_ops __initdata = { diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile index 9e809a7c05c..45da805fb23 100644 --- a/arch/arm/mach-orion5x/Makefile +++ b/arch/arm/mach-orion5x/Makefile @@ -1,4 +1,4 @@ -obj-y				+= common.o addr-map.o pci.o irq.o mpp.o +obj-y				+= common.o pci.o irq.o mpp.o  obj-$(CONFIG_MACH_DB88F5281)	+= db88f5281-setup.o  obj-$(CONFIG_MACH_RD88F5182)	+= rd88f5182-setup.o  obj-$(CONFIG_MACH_KUROBOX_PRO)	+= kurobox_pro-setup.o diff --git a/arch/arm/mach-orion5x/addr-map.c b/arch/arm/mach-orion5x/addr-map.c deleted file mode 100644 index b5efc0fd31c..00000000000 --- a/arch/arm/mach-orion5x/addr-map.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * arch/arm/mach-orion5x/addr-map.c - * - * Address map functions for Marvell Orion 5x SoCs - * - * Maintainer: Tzachi Perelstein <tzachi@marvell.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/mbus.h> -#include <linux/io.h> -#include <mach/hardware.h> -#include <plat/addr-map.h> -#include "common.h" - -/* - * The Orion has fully programmable address map. There's a separate address - * map for each of the device _master_ interfaces, e.g. CPU, PCI, PCIe, USB, - * Gigabit Ethernet, DMA/XOR engines, etc. Each interface has its own - * address decode windows that allow it to access any of the Orion resources. - * - * CPU address decoding -- - * Linux assumes that it is the boot loader that already setup the access to - * DDR and internal registers. - * Setup access to PCI and PCIe IO/MEM space is issued by this file. - * Setup access to various devices located on the device bus interface (e.g. - * flashes, RTC, etc) should be issued by machine-setup.c according to - * specific board population (by using orion5x_setup_*_win()). - * - * Non-CPU Masters address decoding -- - * Unlike the CPU, we setup the access from Orion's master interfaces to DDR - * banks only (the typical use case). - * Setup access for each master to DDR is issued by platform device setup. - */ - -/* - * Generic Address Decode Windows bit settings - */ -#define TARGET_DEV_BUS		1 -#define TARGET_PCI		3 -#define TARGET_PCIE		4 -#define TARGET_SRAM		9 -#define ATTR_PCIE_MEM		0x59 -#define ATTR_PCIE_IO		0x51 -#define ATTR_PCIE_WA		0x79 -#define ATTR_PCI_MEM		0x59 -#define ATTR_PCI_IO		0x51 -#define ATTR_DEV_CS0		0x1e -#define ATTR_DEV_CS1		0x1d -#define ATTR_DEV_CS2		0x1b -#define ATTR_DEV_BOOT		0xf -#define ATTR_SRAM		0x0 - -static int __initdata win_alloc_count; - -static int __init cpu_win_can_remap(const struct orion_addr_map_cfg *cfg, -		  const int win) -{ -	u32 dev, rev; - -	orion5x_pcie_id(&dev, &rev); -	if ((dev == MV88F5281_DEV_ID && win < 4) -	    || (dev == MV88F5182_DEV_ID && win < 2) -	    || (dev == MV88F5181_DEV_ID && win < 2) -	    || (dev == MV88F6183_DEV_ID && win < 4)) -		return 1; - -	return 0; -} - -/* - * Description of the windows needed by the platform code - */ -static struct orion_addr_map_cfg addr_map_cfg __initdata = { -	.num_wins = 8, -	.cpu_win_can_remap = cpu_win_can_remap, -	.bridge_virt_base = ORION5X_BRIDGE_VIRT_BASE, -}; - -static const struct __initdata orion_addr_map_info addr_map_info[] = { -	/* -	 * Setup windows for PCI+PCIe IO+MEM space. -	 */ -	{ 0, ORION5X_PCIE_IO_PHYS_BASE, ORION5X_PCIE_IO_SIZE, -	  TARGET_PCIE, ATTR_PCIE_IO, ORION5X_PCIE_IO_BUS_BASE -	}, -	{ 1, ORION5X_PCI_IO_PHYS_BASE, ORION5X_PCI_IO_SIZE, -	  TARGET_PCI, ATTR_PCI_IO, ORION5X_PCI_IO_BUS_BASE -	}, -	{ 2, ORION5X_PCIE_MEM_PHYS_BASE, ORION5X_PCIE_MEM_SIZE, -	  TARGET_PCIE, ATTR_PCIE_MEM, -1 -	}, -	{ 3, ORION5X_PCI_MEM_PHYS_BASE, ORION5X_PCI_MEM_SIZE, -	  TARGET_PCI, ATTR_PCI_MEM, -1 -	}, -	/* End marker */ -	{ -1, 0, 0, 0, 0, 0 } -}; - -void __init orion5x_setup_cpu_mbus_bridge(void) -{ -	/* -	 * Disable, clear and configure windows. -	 */ -	orion_config_wins(&addr_map_cfg, addr_map_info); -	win_alloc_count = 4; - -	/* -	 * Setup MBUS dram target info. -	 */ -	orion_setup_cpu_mbus_target(&addr_map_cfg, -				    (void __iomem *) ORION5X_DDR_WINDOW_CPU_BASE); -} - -void __init orion5x_setup_dev_boot_win(u32 base, u32 size) -{ -	orion_setup_cpu_win(&addr_map_cfg, win_alloc_count++, base, size, -			    TARGET_DEV_BUS, ATTR_DEV_BOOT, -1); -} - -void __init orion5x_setup_dev0_win(u32 base, u32 size) -{ -	orion_setup_cpu_win(&addr_map_cfg, win_alloc_count++, base, size, -			    TARGET_DEV_BUS, ATTR_DEV_CS0, -1); -} - -void __init orion5x_setup_dev1_win(u32 base, u32 size) -{ -	orion_setup_cpu_win(&addr_map_cfg, win_alloc_count++, base, size, -			    TARGET_DEV_BUS, ATTR_DEV_CS1, -1); -} - -void __init orion5x_setup_dev2_win(u32 base, u32 size) -{ -	orion_setup_cpu_win(&addr_map_cfg, win_alloc_count++, base, size, -			    TARGET_DEV_BUS, ATTR_DEV_CS2, -1); -} - -void __init orion5x_setup_pcie_wa_win(u32 base, u32 size) -{ -	orion_setup_cpu_win(&addr_map_cfg, win_alloc_count++, base, size, -			    TARGET_PCIE, ATTR_PCIE_WA, -1); -} - -void __init orion5x_setup_sram_win(void) -{ -	orion_setup_cpu_win(&addr_map_cfg, win_alloc_count++, -			    ORION5X_SRAM_PHYS_BASE, ORION5X_SRAM_SIZE, -			    TARGET_SRAM, ATTR_SRAM, -1); -} diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c index 94fbb815680..b91002ca92f 100644 --- a/arch/arm/mach-orion5x/board-dt.c +++ b/arch/arm/mach-orion5x/board-dt.c @@ -42,7 +42,7 @@ static void __init orion5x_dt_init(void)  	/*  	 * Setup Orion address map  	 */ -	orion5x_setup_cpu_mbus_bridge(); +	orion5x_setup_wins();  	/* Setup root of clk tree */  	clk_init(); diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index 2075bf8e3d9..b97fd672e89 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -35,7 +35,6 @@  #include <linux/platform_data/usb-ehci-orion.h>  #include <plat/time.h>  #include <plat/common.h> -#include <plat/addr-map.h>  #include "common.h"  /***************************************************************************** @@ -175,7 +174,8 @@ void __init orion5x_xor_init(void)   ****************************************************************************/  static void __init orion5x_crypto_init(void)  { -	orion5x_setup_sram_win(); +	mvebu_mbus_add_window("sram", ORION5X_SRAM_PHYS_BASE, +			      ORION5X_SRAM_SIZE);  	orion_crypto_init(ORION5X_CRYPTO_PHYS_BASE, ORION5X_SRAM_PHYS_BASE,  			  SZ_8K, IRQ_ORION5X_CESA);  } @@ -194,6 +194,9 @@ void __init orion5x_wdt_init(void)   ****************************************************************************/  void __init orion5x_init_early(void)  { +	u32 rev, dev; +	const char *mbus_soc_name; +  	orion_time_set_base(TIMER_VIRT_BASE);  	/* @@ -202,6 +205,46 @@ void __init orion5x_init_early(void)  	 * the allocations won't fail.  	 */  	init_dma_coherent_pool_size(SZ_1M); + +	/* Initialize the MBUS driver */ +	orion5x_pcie_id(&dev, &rev); +	if (dev == MV88F5281_DEV_ID) +		mbus_soc_name = "marvell,orion5x-88f5281-mbus"; +	else if (dev == MV88F5182_DEV_ID) +		mbus_soc_name = "marvell,orion5x-88f5182-mbus"; +	else if (dev == MV88F5181_DEV_ID) +		mbus_soc_name = "marvell,orion5x-88f5181-mbus"; +	else if (dev == MV88F6183_DEV_ID) +		mbus_soc_name = "marvell,orion5x-88f6183-mbus"; +	else +		mbus_soc_name = NULL; +	mvebu_mbus_init(mbus_soc_name, ORION5X_BRIDGE_WINS_BASE, +			ORION5X_BRIDGE_WINS_SZ, +			ORION5X_DDR_WINS_BASE, ORION5X_DDR_WINS_SZ); +} + +void orion5x_setup_wins(void) +{ +	/* +	 * The PCIe windows will no longer be statically allocated +	 * here once Orion5x is migrated to the pci-mvebu driver. +	 */ +	mvebu_mbus_add_window_remap_flags("pcie0.0", ORION5X_PCIE_IO_PHYS_BASE, +					  ORION5X_PCIE_IO_SIZE, +					  ORION5X_PCIE_IO_BUS_BASE, +					  MVEBU_MBUS_PCI_IO); +	mvebu_mbus_add_window_remap_flags("pcie0.0", ORION5X_PCIE_MEM_PHYS_BASE, +					  ORION5X_PCIE_MEM_SIZE, +					  MVEBU_MBUS_NO_REMAP, +					  MVEBU_MBUS_PCI_MEM); +	mvebu_mbus_add_window_remap_flags("pci0.0", ORION5X_PCI_IO_PHYS_BASE, +					  ORION5X_PCI_IO_SIZE, +					  ORION5X_PCI_IO_BUS_BASE, +					  MVEBU_MBUS_PCI_IO); +	mvebu_mbus_add_window_remap_flags("pci0.0", ORION5X_PCI_MEM_PHYS_BASE, +					  ORION5X_PCI_MEM_SIZE, +					  MVEBU_MBUS_NO_REMAP, +					  MVEBU_MBUS_PCI_MEM);  }  int orion5x_tclk; @@ -283,7 +326,7 @@ void __init orion5x_init(void)  	/*  	 * Setup Orion address map  	 */ -	orion5x_setup_cpu_mbus_bridge(); +	orion5x_setup_wins();  	/* Setup root of clk tree */  	clk_init(); diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h index e6034576028..cdaa01f3d18 100644 --- a/arch/arm/mach-orion5x/common.h +++ b/arch/arm/mach-orion5x/common.h @@ -17,18 +17,7 @@ void clk_init(void);  extern int orion5x_tclk;  extern void orion5x_timer_init(void); -/* - * Enumerations and functions for Orion windows mapping. Used by Orion core - * functions to map its interfaces and by the machine-setup to map its on- - * board devices. Details in /mach-orion/addr-map.c - */ -void orion5x_setup_cpu_mbus_bridge(void); -void orion5x_setup_dev_boot_win(u32 base, u32 size); -void orion5x_setup_dev0_win(u32 base, u32 size); -void orion5x_setup_dev1_win(u32 base, u32 size); -void orion5x_setup_dev2_win(u32 base, u32 size); -void orion5x_setup_pcie_wa_win(u32 base, u32 size); -void orion5x_setup_sram_win(void); +void orion5x_setup_wins(void);  void orion5x_ehci0_init(void);  void orion5x_ehci1_init(void); diff --git a/arch/arm/mach-orion5x/d2net-setup.c b/arch/arm/mach-orion5x/d2net-setup.c index 57d0af74874..16c88bbabc9 100644 --- a/arch/arm/mach-orion5x/d2net-setup.c +++ b/arch/arm/mach-orion5x/d2net-setup.c @@ -317,8 +317,8 @@ static void __init d2net_init(void)  	d2net_sata_power_init();  	orion5x_sata_init(&d2net_sata_data); -	orion5x_setup_dev_boot_win(D2NET_NOR_BOOT_BASE, -				D2NET_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", D2NET_NOR_BOOT_BASE, +			      D2NET_NOR_BOOT_SIZE);  	platform_device_register(&d2net_nor_flash);  	platform_device_register(&d2net_gpio_buttons); diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c index 76665640087..4e1263da38b 100644 --- a/arch/arm/mach-orion5x/db88f5281-setup.c +++ b/arch/arm/mach-orion5x/db88f5281-setup.c @@ -340,16 +340,19 @@ static void __init db88f5281_init(void)  	orion5x_uart0_init();  	orion5x_uart1_init(); -	orion5x_setup_dev_boot_win(DB88F5281_NOR_BOOT_BASE, -				DB88F5281_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", DB88F5281_NOR_BOOT_BASE, +			      DB88F5281_NOR_BOOT_SIZE);  	platform_device_register(&db88f5281_boot_flash); -	orion5x_setup_dev0_win(DB88F5281_7SEG_BASE, DB88F5281_7SEG_SIZE); +	mvebu_mbus_add_window("devbus-cs0", DB88F5281_7SEG_BASE, +			      DB88F5281_7SEG_SIZE); -	orion5x_setup_dev1_win(DB88F5281_NOR_BASE, DB88F5281_NOR_SIZE); +	mvebu_mbus_add_window("devbus-cs1", DB88F5281_NOR_BASE, +			      DB88F5281_NOR_SIZE);  	platform_device_register(&db88f5281_nor_flash); -	orion5x_setup_dev2_win(DB88F5281_NAND_BASE, DB88F5281_NAND_SIZE); +	mvebu_mbus_add_window("devbus-cs2", DB88F5281_NAND_BASE, +			      DB88F5281_NAND_SIZE);  	platform_device_register(&db88f5281_nand_flash);  	i2c_register_board_info(0, &db88f5281_i2c_rtc, 1); diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c index 6eb1732757f..9e6baf581ed 100644 --- a/arch/arm/mach-orion5x/dns323-setup.c +++ b/arch/arm/mach-orion5x/dns323-setup.c @@ -611,7 +611,8 @@ static void __init dns323_init(void)  	/* setup flash mapping  	 * CS3 holds a 8 MB Spansion S29GL064M90TFIR4  	 */ -	orion5x_setup_dev_boot_win(DNS323_NOR_BOOT_BASE, DNS323_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", DNS323_NOR_BOOT_BASE, +			      DNS323_NOR_BOOT_SIZE);  	platform_device_register(&dns323_nor_flash);  	/* Sort out LEDs, Buttons and i2c devices */ diff --git a/arch/arm/mach-orion5x/edmini_v2-setup.c b/arch/arm/mach-orion5x/edmini_v2-setup.c index d675e727803..147615510dd 100644 --- a/arch/arm/mach-orion5x/edmini_v2-setup.c +++ b/arch/arm/mach-orion5x/edmini_v2-setup.c @@ -154,8 +154,8 @@ void __init edmini_v2_init(void)  	orion5x_ehci0_init();  	orion5x_eth_init(&edmini_v2_eth_data); -	orion5x_setup_dev_boot_win(EDMINI_V2_NOR_BOOT_BASE, -				EDMINI_V2_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", EDMINI_V2_NOR_BOOT_BASE, +			      EDMINI_V2_NOR_BOOT_SIZE);  	platform_device_register(&edmini_v2_nor_flash);  	pr_notice("edmini_v2: USB device port, flash write and power-off " diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h index d265f5484a8..b78ff324886 100644 --- a/arch/arm/mach-orion5x/include/mach/orion5x.h +++ b/arch/arm/mach-orion5x/include/mach/orion5x.h @@ -66,8 +66,10 @@   * Orion Registers Map   ******************************************************************************/ +#define ORION5X_DDR_PHYS_BASE           (ORION5X_REGS_PHYS_BASE + 0x00000) +#define  ORION5X_DDR_WINS_BASE          (ORION5X_DDR_PHYS_BASE + 0x1500) +#define  ORION5X_DDR_WINS_SZ            (0x10)  #define ORION5X_DDR_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x00000) -#define  ORION5X_DDR_WINDOW_CPU_BASE    (ORION5X_DDR_VIRT_BASE + 0x1500)  #define ORION5X_DEV_BUS_PHYS_BASE	(ORION5X_REGS_PHYS_BASE + 0x10000)  #define ORION5X_DEV_BUS_VIRT_BASE	(ORION5X_REGS_VIRT_BASE + 0x10000)  #define ORION5X_DEV_BUS_REG(x)		(ORION5X_DEV_BUS_VIRT_BASE + (x)) @@ -81,6 +83,8 @@  #define ORION5X_BRIDGE_VIRT_BASE	(ORION5X_REGS_VIRT_BASE + 0x20000)  #define ORION5X_BRIDGE_PHYS_BASE	(ORION5X_REGS_PHYS_BASE + 0x20000) +#define  ORION5X_BRIDGE_WINS_BASE       (ORION5X_BRIDGE_PHYS_BASE) +#define  ORION5X_BRIDGE_WINS_SZ         (0x80)  #define ORION5X_PCI_VIRT_BASE		(ORION5X_REGS_VIRT_BASE + 0x30000) diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c index b9840352621..aae10e4a917 100644 --- a/arch/arm/mach-orion5x/kurobox_pro-setup.c +++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c @@ -359,13 +359,13 @@ static void __init kurobox_pro_init(void)  	orion5x_uart1_init();  	orion5x_xor_init(); -	orion5x_setup_dev_boot_win(KUROBOX_PRO_NOR_BOOT_BASE, -				   KUROBOX_PRO_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", KUROBOX_PRO_NOR_BOOT_BASE, +			      KUROBOX_PRO_NOR_BOOT_SIZE);  	platform_device_register(&kurobox_pro_nor_flash);  	if (machine_is_kurobox_pro()) { -		orion5x_setup_dev0_win(KUROBOX_PRO_NAND_BASE, -				       KUROBOX_PRO_NAND_SIZE); +		mvebu_mbus_add_window("devbus-cs0", KUROBOX_PRO_NAND_BASE, +				      KUROBOX_PRO_NAND_SIZE);  		platform_device_register(&kurobox_pro_nand_flash);  	} diff --git a/arch/arm/mach-orion5x/ls-chl-setup.c b/arch/arm/mach-orion5x/ls-chl-setup.c index 044da5b6a6a..24f4e14e589 100644 --- a/arch/arm/mach-orion5x/ls-chl-setup.c +++ b/arch/arm/mach-orion5x/ls-chl-setup.c @@ -294,8 +294,8 @@ static void __init lschl_init(void)  	orion5x_uart0_init();  	orion5x_xor_init(); -	orion5x_setup_dev_boot_win(LSCHL_NOR_BOOT_BASE, -				   LSCHL_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", LSCHL_NOR_BOOT_BASE, +			      LSCHL_NOR_BOOT_SIZE);  	platform_device_register(&lschl_nor_flash);  	platform_device_register(&lschl_leds); diff --git a/arch/arm/mach-orion5x/ls_hgl-setup.c b/arch/arm/mach-orion5x/ls_hgl-setup.c index d49f93423f5..fc653bb41e7 100644 --- a/arch/arm/mach-orion5x/ls_hgl-setup.c +++ b/arch/arm/mach-orion5x/ls_hgl-setup.c @@ -243,8 +243,8 @@ static void __init ls_hgl_init(void)  	orion5x_uart0_init();  	orion5x_xor_init(); -	orion5x_setup_dev_boot_win(LS_HGL_NOR_BOOT_BASE, -				   LS_HGL_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", LS_HGL_NOR_BOOT_BASE, +			      LS_HGL_NOR_BOOT_SIZE);  	platform_device_register(&ls_hgl_nor_flash);  	platform_device_register(&ls_hgl_button_device); diff --git a/arch/arm/mach-orion5x/lsmini-setup.c b/arch/arm/mach-orion5x/lsmini-setup.c index 8e3965c6c0f..18e66e617dc 100644 --- a/arch/arm/mach-orion5x/lsmini-setup.c +++ b/arch/arm/mach-orion5x/lsmini-setup.c @@ -244,8 +244,8 @@ static void __init lsmini_init(void)  	orion5x_uart0_init();  	orion5x_xor_init(); -	orion5x_setup_dev_boot_win(LSMINI_NOR_BOOT_BASE, -				   LSMINI_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", LSMINI_NOR_BOOT_BASE, +			      LSMINI_NOR_BOOT_SIZE);  	platform_device_register(&lsmini_nor_flash);  	platform_device_register(&lsmini_button_device); diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c index 0ec94a1f2b1..827acbafc9d 100644 --- a/arch/arm/mach-orion5x/mss2-setup.c +++ b/arch/arm/mach-orion5x/mss2-setup.c @@ -241,7 +241,8 @@ static void __init mss2_init(void)  	orion5x_uart0_init();  	orion5x_xor_init(); -	orion5x_setup_dev_boot_win(MSS2_NOR_BOOT_BASE, MSS2_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", MSS2_NOR_BOOT_BASE, +			      MSS2_NOR_BOOT_SIZE);  	platform_device_register(&mss2_nor_flash);  	platform_device_register(&mss2_button_device); diff --git a/arch/arm/mach-orion5x/mv2120-setup.c b/arch/arm/mach-orion5x/mv2120-setup.c index 18143f2a909..92600ae2b4b 100644 --- a/arch/arm/mach-orion5x/mv2120-setup.c +++ b/arch/arm/mach-orion5x/mv2120-setup.c @@ -204,7 +204,8 @@ static void __init mv2120_init(void)  	orion5x_uart0_init();  	orion5x_xor_init(); -	orion5x_setup_dev_boot_win(MV2120_NOR_BOOT_BASE, MV2120_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", MV2120_NOR_BOOT_BASE, +			      MV2120_NOR_BOOT_SIZE);  	platform_device_register(&mv2120_nor_flash);  	platform_device_register(&mv2120_button_device); diff --git a/arch/arm/mach-orion5x/net2big-setup.c b/arch/arm/mach-orion5x/net2big-setup.c index 282e503b003..dd0641a0d07 100644 --- a/arch/arm/mach-orion5x/net2big-setup.c +++ b/arch/arm/mach-orion5x/net2big-setup.c @@ -397,8 +397,8 @@ static void __init net2big_init(void)  	net2big_sata_power_init();  	orion5x_sata_init(&net2big_sata_data); -	orion5x_setup_dev_boot_win(NET2BIG_NOR_BOOT_BASE, -				   NET2BIG_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", NET2BIG_NOR_BOOT_BASE, +			      NET2BIG_NOR_BOOT_SIZE);  	platform_device_register(&net2big_nor_flash);  	platform_device_register(&net2big_gpio_buttons); diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index 973db98a3c2..503368023bb 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -157,8 +157,11 @@ static int __init pcie_setup(struct pci_sys_data *sys)  	if (dev == MV88F5181_DEV_ID || dev == MV88F5182_DEV_ID) {  		printk(KERN_NOTICE "Applying Orion-1/Orion-NAS PCIe config "  				   "read transaction workaround\n"); -		orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE, -					  ORION5X_PCIE_WA_SIZE); +		mvebu_mbus_add_window_remap_flags("pcie0.0", +						  ORION5X_PCIE_WA_PHYS_BASE, +						  ORION5X_PCIE_WA_SIZE, +						  MVEBU_MBUS_NO_REMAP, +						  MVEBU_MBUS_PCI_WA);  		pcie_ops.read = pcie_rd_conf_wa;  	} diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c index d6e72f672af..1c4498bf650 100644 --- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c +++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c @@ -123,8 +123,8 @@ static void __init rd88f5181l_fxo_init(void)  	orion5x_eth_switch_init(&rd88f5181l_fxo_switch_plat_data, NO_IRQ);  	orion5x_uart0_init(); -	orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE, -				   RD88F5181L_FXO_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", RD88F5181L_FXO_NOR_BOOT_BASE, +			      RD88F5181L_FXO_NOR_BOOT_SIZE);  	platform_device_register(&rd88f5181l_fxo_nor_boot_flash);  } diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c index c8b7913310e..adabe34c4fc 100644 --- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c @@ -130,8 +130,8 @@ static void __init rd88f5181l_ge_init(void)  	orion5x_i2c_init();  	orion5x_uart0_init(); -	orion5x_setup_dev_boot_win(RD88F5181L_GE_NOR_BOOT_BASE, -				   RD88F5181L_GE_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", RD88F5181L_GE_NOR_BOOT_BASE, +			      RD88F5181L_GE_NOR_BOOT_SIZE);  	platform_device_register(&rd88f5181l_ge_nor_boot_flash);  	i2c_register_board_info(0, &rd88f5181l_ge_i2c_rtc, 1); diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c index f9e156725d7..66e77ec9153 100644 --- a/arch/arm/mach-orion5x/rd88f5182-setup.c +++ b/arch/arm/mach-orion5x/rd88f5182-setup.c @@ -264,10 +264,11 @@ static void __init rd88f5182_init(void)  	orion5x_uart0_init();  	orion5x_xor_init(); -	orion5x_setup_dev_boot_win(RD88F5182_NOR_BOOT_BASE, -				   RD88F5182_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", RD88F5182_NOR_BOOT_BASE, +			      RD88F5182_NOR_BOOT_SIZE); -	orion5x_setup_dev1_win(RD88F5182_NOR_BASE, RD88F5182_NOR_SIZE); +	mvebu_mbus_add_window("devbus-cs1", RD88F5182_NOR_BASE, +			      RD88F5182_NOR_SIZE);  	platform_device_register(&rd88f5182_nor_flash);  	platform_device_register(&rd88f5182_gpio_leds); diff --git a/arch/arm/mach-orion5x/terastation_pro2-setup.c b/arch/arm/mach-orion5x/terastation_pro2-setup.c index acc0877ec1c..a0bfa53e755 100644 --- a/arch/arm/mach-orion5x/terastation_pro2-setup.c +++ b/arch/arm/mach-orion5x/terastation_pro2-setup.c @@ -329,8 +329,8 @@ static void __init tsp2_init(void)  	/*  	 * Configure peripherals.  	 */ -	orion5x_setup_dev_boot_win(TSP2_NOR_BOOT_BASE, -				   TSP2_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", TSP2_NOR_BOOT_BASE, +			      TSP2_NOR_BOOT_SIZE);  	platform_device_register(&tsp2_nor_flash);  	orion5x_ehci0_init(); diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c index 9c17f0c2b48..80174f0f168 100644 --- a/arch/arm/mach-orion5x/ts209-setup.c +++ b/arch/arm/mach-orion5x/ts209-setup.c @@ -286,8 +286,8 @@ static void __init qnap_ts209_init(void)  	/*  	 * Configure peripherals.  	 */ -	orion5x_setup_dev_boot_win(QNAP_TS209_NOR_BOOT_BASE, -				   QNAP_TS209_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", QNAP_TS209_NOR_BOOT_BASE, +			      QNAP_TS209_NOR_BOOT_SIZE);  	platform_device_register(&qnap_ts209_nor_flash);  	orion5x_ehci0_init(); diff --git a/arch/arm/mach-orion5x/ts409-setup.c b/arch/arm/mach-orion5x/ts409-setup.c index 8cc5ab6c503..92592790d6d 100644 --- a/arch/arm/mach-orion5x/ts409-setup.c +++ b/arch/arm/mach-orion5x/ts409-setup.c @@ -277,8 +277,8 @@ static void __init qnap_ts409_init(void)  	/*  	 * Configure peripherals.  	 */ -	orion5x_setup_dev_boot_win(QNAP_TS409_NOR_BOOT_BASE, -				   QNAP_TS409_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", QNAP_TS409_NOR_BOOT_BASE, +			      QNAP_TS409_NOR_BOOT_SIZE);  	platform_device_register(&qnap_ts409_nor_flash);  	orion5x_ehci0_init(); diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c index 66552ca7e05..6b84863c018 100644 --- a/arch/arm/mach-orion5x/wnr854t-setup.c +++ b/arch/arm/mach-orion5x/wnr854t-setup.c @@ -127,8 +127,8 @@ static void __init wnr854t_init(void)  	orion5x_eth_switch_init(&wnr854t_switch_plat_data, NO_IRQ);  	orion5x_uart0_init(); -	orion5x_setup_dev_boot_win(WNR854T_NOR_BOOT_BASE, -				   WNR854T_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", WNR854T_NOR_BOOT_BASE, +			      WNR854T_NOR_BOOT_SIZE);  	platform_device_register(&wnr854t_nor_flash);  } diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c index 2c5408e2e68..fae684bc54f 100644 --- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c +++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c @@ -213,8 +213,8 @@ static void __init wrt350n_v2_init(void)  	orion5x_eth_switch_init(&wrt350n_v2_switch_plat_data, NO_IRQ);  	orion5x_uart0_init(); -	orion5x_setup_dev_boot_win(WRT350N_V2_NOR_BOOT_BASE, -				   WRT350N_V2_NOR_BOOT_SIZE); +	mvebu_mbus_add_window("devbus-boot", WRT350N_V2_NOR_BOOT_BASE, +			      WRT350N_V2_NOR_BOOT_SIZE);  	platform_device_register(&wrt350n_v2_nor_flash);  	platform_device_register(&wrt350n_v2_leds);  	platform_device_register(&wrt350n_v2_button_device); diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index 7d86bfbb5b0..31d5cd4d978 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -26,6 +26,25 @@  #include <mach/clock.h>  #include <mach/common.h> +/* + *		MD1 = 1			MD1 = 0 + *		(PLLA = 1500)		(PLLA = 1600) + *		(MHz)			(MHz) + *------------------------------------------------+-------------------- + * clkz		1000   (2/3)		800   (1/2) + * clkzs	 250   (1/6)		200   (1/8) + * clki		 750   (1/2)		800   (1/2) + * clks		 250   (1/6)		200   (1/8) + * clks1	 125   (1/12)		100   (1/16) + * clks3	 187.5 (1/8)		200   (1/8) + * clks4	  93.7 (1/16)		100   (1/16) + * clkp		  62.5 (1/24)		 50   (1/32) + * clkg		  62.5 (1/24)		 66.6 (1/24) + * clkb, CLKOUT + * (MD2 = 0)	  62.5 (1/24)		 66.6 (1/24) + * (MD2 = 1)	  41.6 (1/36)		 50   (1/32) +*/ +  #define MD(nr)	BIT(nr)  #define FRQMR		IOMEM(0xffc80014) @@ -93,7 +112,7 @@ static struct clk *main_clks[] = {  };  enum { MSTP323, MSTP322, MSTP321, MSTP320, -	MSTP115, +	MSTP115, MSTP114,  	MSTP103, MSTP101, MSTP100,  	MSTP030,  	MSTP029, MSTP028, MSTP027, MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021, @@ -107,6 +126,7 @@ static struct clk mstp_clks[MSTP_NR] = {  	[MSTP321] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 21, 0), /* SDHI2 */  	[MSTP320] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 20, 0), /* SDHI3 */  	[MSTP115] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 15, 0), /* SATA */ +	[MSTP114] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 14, 0), /* Ether */  	[MSTP103] = SH_CLK_MSTP32(&clks_clk, MSTPCR1,  3, 0), /* DU */  	[MSTP101] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1,  1, 0), /* USB2 */  	[MSTP100] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1,  0, 0), /* USB0/1 */ @@ -143,6 +163,7 @@ static struct clk_lookup lookups[] = {  	/* MSTP32 clocks */  	CLKDEV_DEV_ID("sata_rcar", &mstp_clks[MSTP115]), /* SATA */  	CLKDEV_DEV_ID("fc600000.sata", &mstp_clks[MSTP115]), /* SATA w/DT */ +	CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP114]), /* Ether */  	CLKDEV_DEV_ID("ehci-platform.1", &mstp_clks[MSTP101]), /* USB EHCI port2 */  	CLKDEV_DEV_ID("ohci-platform.1", &mstp_clks[MSTP101]), /* USB OHCI port2 */  	CLKDEV_DEV_ID("ehci-platform.0", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */ diff --git a/arch/arm/mach-shmobile/include/mach/r8a7779.h b/arch/arm/mach-shmobile/include/mach/r8a7779.h index 945299ed163..188b295938a 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7779.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7779.h @@ -3,6 +3,7 @@  #include <linux/sh_clk.h>  #include <linux/pm_domain.h> +#include <linux/sh_eth.h>  struct platform_device; @@ -31,6 +32,7 @@ extern void r8a7779_earlytimer_init(void);  extern void r8a7779_add_early_devices(void);  extern void r8a7779_add_standard_devices(void);  extern void r8a7779_add_standard_devices_dt(void); +extern void r8a7779_add_ether_device(struct sh_eth_plat_data *pdata);  extern void r8a7779_clock_init(void);  extern void r8a7779_pinmux_init(void);  extern void r8a7779_pm_init(void); diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index a460ba3dedc..b0b394842ea 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -1,8 +1,9 @@  /*   * r8a7779 processor support   * - * Copyright (C) 2011  Renesas Solutions Corp. + * Copyright (C) 2011, 2013  Renesas Solutions Corp.   * Copyright (C) 2011  Magnus Damm + * Copyright (C) 2013  Cogent Embedded, Inc.   *   * 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 @@ -393,6 +394,18 @@ static struct platform_device sata_device = {  	},  }; +/* Ether */ +static struct resource ether_resources[] = { +	{ +		.start	= 0xfde00000, +		.end	= 0xfde003ff, +		.flags	= IORESOURCE_MEM, +	}, { +		.start	= gic_iid(0xb4), +		.flags	= IORESOURCE_IRQ, +	}, +}; +  static struct platform_device *r8a7779_devices_dt[] __initdata = {  	&scif0_device,  	&scif1_device, @@ -428,6 +441,14 @@ void __init r8a7779_add_standard_devices(void)  			    ARRAY_SIZE(r8a7779_late_devices));  } +void __init r8a7779_add_ether_device(struct sh_eth_plat_data *pdata) +{ +	platform_device_register_resndata(&platform_bus, "sh_eth", -1, +					  ether_resources, +					  ARRAY_SIZE(ether_resources), +					  pdata, sizeof(*pdata)); +} +  /* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */  void __init __weak r8a7779_register_twd(void) { } diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index cf3226b041f..c1d61f281e6 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig @@ -10,6 +10,7 @@ config ARCH_ZYNQ  	select ICST  	select MIGHT_HAVE_CACHE_L2X0  	select USE_OF +	select HAVE_SMP  	select SPARSE_IRQ  	select CADENCE_TTC_TIMER  	help diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile index 320faedeb48..1b25d92ebf2 100644 --- a/arch/arm/mach-zynq/Makefile +++ b/arch/arm/mach-zynq/Makefile @@ -3,4 +3,8 @@  #  # Common support -obj-y				:= common.o +obj-y				:= common.o slcr.o +CFLAGS_REMOVE_hotplug.o		=-march=armv6k +CFLAGS_hotplug.o 		=-Wa,-march=armv7-a -mcpu=cortex-a9 +obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o +obj-$(CONFIG_SMP)		+= headsmp.o platsmp.o diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 68e0907de5d..5bfe7035b73 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -33,20 +33,23 @@  #include <asm/mach-types.h>  #include <asm/page.h>  #include <asm/pgtable.h> +#include <asm/smp_scu.h>  #include <asm/hardware/cache-l2x0.h>  #include "common.h" +void __iomem *zynq_scu_base; +  static struct of_device_id zynq_of_bus_ids[] __initdata = {  	{ .compatible = "simple-bus", },  	{}  };  /** - * xilinx_init_machine() - System specific initialization, intended to be - *			   called from board specific initialization. + * zynq_init_machine - System specific initialization, intended to be + *		       called from board specific initialization.   */ -static void __init xilinx_init_machine(void) +static void __init zynq_init_machine(void)  {  	/*  	 * 64KB way size, 8-way associativity, parity disabled @@ -56,50 +59,56 @@ static void __init xilinx_init_machine(void)  	of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL);  } -#define SCU_PERIPH_PHYS		0xF8F00000 -#define SCU_PERIPH_SIZE		SZ_8K -#define SCU_PERIPH_VIRT		(VMALLOC_END - SCU_PERIPH_SIZE) +static void __init zynq_timer_init(void) +{ +	zynq_slcr_init(); +	clocksource_of_init(); +} -static struct map_desc scu_desc __initdata = { -	.virtual	= SCU_PERIPH_VIRT, -	.pfn		= __phys_to_pfn(SCU_PERIPH_PHYS), -	.length		= SCU_PERIPH_SIZE, -	.type		= MT_DEVICE, +static struct map_desc zynq_cortex_a9_scu_map __initdata = { +	.length	= SZ_256, +	.type	= MT_DEVICE,  }; -static void __init xilinx_zynq_timer_init(void) +static void __init zynq_scu_map_io(void)  { -	struct device_node *np; -	void __iomem *slcr; - -	np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr"); -	slcr = of_iomap(np, 0); -	WARN_ON(!slcr); +	unsigned long base; -	xilinx_zynq_clocks_init(slcr); - -	clocksource_of_init(); +	base = scu_a9_get_base(); +	zynq_cortex_a9_scu_map.pfn = __phys_to_pfn(base); +	/* Expected address is in vmalloc area that's why simple assign here */ +	zynq_cortex_a9_scu_map.virtual = base; +	iotable_init(&zynq_cortex_a9_scu_map, 1); +	zynq_scu_base = (void __iomem *)base; +	BUG_ON(!zynq_scu_base);  }  /** - * xilinx_map_io() - Create memory mappings needed for early I/O. + * zynq_map_io - Create memory mappings needed for early I/O.   */ -static void __init xilinx_map_io(void) +static void __init zynq_map_io(void)  {  	debug_ll_io_init(); -	iotable_init(&scu_desc, 1); +	zynq_scu_map_io(); +} + +static void zynq_system_reset(char mode, const char *cmd) +{ +	zynq_slcr_system_reset();  } -static const char *xilinx_dt_match[] = { +static const char * const zynq_dt_match[] = {  	"xlnx,zynq-zc702",  	"xlnx,zynq-7000",  	NULL  };  MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") -	.map_io		= xilinx_map_io, +	.smp		= smp_ops(zynq_smp_ops), +	.map_io		= zynq_map_io,  	.init_irq	= irqchip_init, -	.init_machine	= xilinx_init_machine, -	.init_time	= xilinx_zynq_timer_init, -	.dt_compat	= xilinx_dt_match, +	.init_machine	= zynq_init_machine, +	.init_time	= zynq_timer_init, +	.dt_compat	= zynq_dt_match, +	.restart	= zynq_system_reset,  MACHINE_END diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index 5050bb10bb1..fbbd0e21c40 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -17,4 +17,24 @@  #ifndef __MACH_ZYNQ_COMMON_H__  #define __MACH_ZYNQ_COMMON_H__ +extern int zynq_slcr_init(void); +extern void zynq_slcr_system_reset(void); +extern void zynq_slcr_cpu_stop(int cpu); +extern void zynq_slcr_cpu_start(int cpu); + +#ifdef CONFIG_SMP +extern void secondary_startup(void); +extern char zynq_secondary_trampoline; +extern char zynq_secondary_trampoline_jump; +extern char zynq_secondary_trampoline_end; +extern int __cpuinit zynq_cpun_start(u32 address, int cpu); +extern struct smp_operations zynq_smp_ops __initdata; +#endif + +extern void __iomem *zynq_slcr_base; +extern void __iomem *zynq_scu_base; + +/* Hotplug */ +extern void zynq_platform_cpu_die(unsigned int cpu); +  #endif diff --git a/arch/arm/mach-zynq/headsmp.S b/arch/arm/mach-zynq/headsmp.S new file mode 100644 index 00000000000..d183cd234a9 --- /dev/null +++ b/arch/arm/mach-zynq/headsmp.S @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Steffen Trumtrar <s.trumtrar@pengutronix.de> + * Copyright (c) 2012-2013 Xilinx + * + * 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 <linux/init.h> + +	__CPUINIT + +ENTRY(zynq_secondary_trampoline) +	ldr	r0, [pc] +	bx	r0 +.globl zynq_secondary_trampoline_jump +zynq_secondary_trampoline_jump: +	/* Space for jumping address */ +	.word	/* cpu 1 */ +.globl zynq_secondary_trampoline_end +zynq_secondary_trampoline_end: + +ENDPROC(zynq_secondary_trampoline) diff --git a/arch/arm/mach-zynq/hotplug.c b/arch/arm/mach-zynq/hotplug.c new file mode 100644 index 00000000000..c89672bd1de --- /dev/null +++ b/arch/arm/mach-zynq/hotplug.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012-2013 Xilinx + * + * based on linux/arch/arm/mach-realview/hotplug.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * 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/errno.h> +#include <linux/smp.h> + +#include <asm/cacheflush.h> +#include <asm/cp15.h> +#include "common.h" + +static inline void zynq_cpu_enter_lowpower(void) +{ +	unsigned int v; + +	flush_cache_all(); +	asm volatile( +	"	mcr	p15, 0, %1, c7, c5, 0\n" +	"	dsb\n" +	/* +	 * Turn off coherency +	 */ +	"	mrc	p15, 0, %0, c1, c0, 1\n" +	"	bic	%0, %0, #0x40\n" +	"	mcr	p15, 0, %0, c1, c0, 1\n" +	"	mrc	p15, 0, %0, c1, c0, 0\n" +	"	bic	%0, %0, %2\n" +	"	mcr	p15, 0, %0, c1, c0, 0\n" +	  : "=&r" (v) +	  : "r" (0), "Ir" (CR_C) +	  : "cc"); +} + +static inline void zynq_cpu_leave_lowpower(void) +{ +	unsigned int v; + +	asm volatile( +	"	mrc	p15, 0, %0, c1, c0, 0\n" +	"	orr	%0, %0, %1\n" +	"	mcr	p15, 0, %0, c1, c0, 0\n" +	"	mrc	p15, 0, %0, c1, c0, 1\n" +	"	orr	%0, %0, #0x40\n" +	"	mcr	p15, 0, %0, c1, c0, 1\n" +	  : "=&r" (v) +	  : "Ir" (CR_C) +	  : "cc"); +} + +static inline void zynq_platform_do_lowpower(unsigned int cpu, int *spurious) +{ +	/* +	 * there is no power-control hardware on this platform, so all +	 * we can do is put the core into WFI; this is safe as the calling +	 * code will have already disabled interrupts +	 */ +	for (;;) { +		dsb(); +		wfi(); + +		/* +		 * Getting here, means that we have come out of WFI without +		 * having been woken up - this shouldn't happen +		 * +		 * Just note it happening - when we're woken, we can report +		 * its occurrence. +		 */ +		(*spurious)++; +	} +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void zynq_platform_cpu_die(unsigned int cpu) +{ +	int spurious = 0; + +	/* +	 * we're ready for shutdown now, so do it +	 */ +	zynq_cpu_enter_lowpower(); +	zynq_platform_do_lowpower(cpu, &spurious); + +	/* +	 * bring this CPU back into the world of cache +	 * coherency, and then restore interrupts +	 */ +	zynq_cpu_leave_lowpower(); + +	if (spurious) +		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c new file mode 100644 index 00000000000..5fc167e0761 --- /dev/null +++ b/arch/arm/mach-zynq/platsmp.c @@ -0,0 +1,136 @@ +/* + * This file contains Xilinx specific SMP code, used to start up + * the second processor. + * + * Copyright (C) 2011-2013 Xilinx + * + * based on linux/arch/arm/mach-realview/platsmp.c + * + * Copyright (C) 2002 ARM Ltd. + * + * 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/export.h> +#include <linux/jiffies.h> +#include <linux/init.h> +#include <linux/io.h> +#include <asm/cacheflush.h> +#include <asm/smp_scu.h> +#include <linux/irqchip/arm-gic.h> +#include "common.h" + +/* + * Store number of cores in the system + * Because of scu_get_core_count() must be in __init section and can't + * be called from zynq_cpun_start() because it is in __cpuinit section. + */ +static int ncores; + +int __cpuinit zynq_cpun_start(u32 address, int cpu) +{ +	u32 trampoline_code_size = &zynq_secondary_trampoline_end - +						&zynq_secondary_trampoline; + +	if (cpu > ncores) { +		pr_warn("CPU No. is not available in the system\n"); +		return -1; +	} + +	/* MS: Expectation that SLCR are directly map and accessible */ +	/* Not possible to jump to non aligned address */ +	if (!(address & 3) && (!address || (address >= trampoline_code_size))) { +		/* Store pointer to ioremap area which points to address 0x0 */ +		static u8 __iomem *zero; +		u32 trampoline_size = &zynq_secondary_trampoline_jump - +						&zynq_secondary_trampoline; + +		zynq_slcr_cpu_stop(cpu); + +		if (__pa(PAGE_OFFSET)) { +			zero = ioremap(0, trampoline_code_size); +			if (!zero) { +				pr_warn("BOOTUP jump vectors not accessible\n"); +				return -1; +			} +		} else { +			zero = (__force u8 __iomem *)PAGE_OFFSET; +		} + +		/* +		 * This is elegant way how to jump to any address +		 * 0x0: Load address at 0x8 to r0 +		 * 0x4: Jump by mov instruction +		 * 0x8: Jumping address +		 */ +		memcpy((__force void *)zero, &zynq_secondary_trampoline, +						trampoline_size); +		writel(address, zero + trampoline_size); + +		flush_cache_all(); +		outer_flush_range(0, trampoline_code_size); +		smp_wmb(); + +		if (__pa(PAGE_OFFSET)) +			iounmap(zero); + +		zynq_slcr_cpu_start(cpu); + +		return 0; +	} + +	pr_warn("Can't start CPU%d: Wrong starting address %x\n", cpu, address); + +	return -1; +} +EXPORT_SYMBOL(zynq_cpun_start); + +static int __cpuinit zynq_boot_secondary(unsigned int cpu, +						struct task_struct *idle) +{ +	return zynq_cpun_start(virt_to_phys(secondary_startup), cpu); +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +static void __init zynq_smp_init_cpus(void) +{ +	int i; + +	ncores = scu_get_core_count(zynq_scu_base); + +	for (i = 0; i < ncores && i < CONFIG_NR_CPUS; i++) +		set_cpu_possible(i, true); +} + +static void __init zynq_smp_prepare_cpus(unsigned int max_cpus) +{ +	int i; + +	/* +	 * Initialise the present map, which describes the set of CPUs +	 * actually populated at the present time. +	 */ +	for (i = 0; i < max_cpus; i++) +		set_cpu_present(i, true); + +	scu_enable(zynq_scu_base); +} + +struct smp_operations zynq_smp_ops __initdata = { +	.smp_init_cpus		= zynq_smp_init_cpus, +	.smp_prepare_cpus	= zynq_smp_prepare_cpus, +	.smp_boot_secondary	= zynq_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU +	.cpu_die		= zynq_platform_cpu_die, +#endif +}; diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c new file mode 100644 index 00000000000..c70969b9c25 --- /dev/null +++ b/arch/arm/mach-zynq/slcr.c @@ -0,0 +1,125 @@ +/* + * Xilinx SLCR driver + * + * Copyright (c) 2011-2013 Xilinx Inc. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA + * 02139, USA. + */ + +#include <linux/export.h> +#include <linux/io.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/clk/zynq.h> +#include "common.h" + +#define SLCR_UNLOCK_MAGIC		0xDF0D +#define SLCR_UNLOCK			0x8   /* SCLR unlock register */ + +#define SLCR_PS_RST_CTRL_OFFSET		0x200 /* PS Software Reset Control */ + +#define SLCR_A9_CPU_CLKSTOP		0x10 +#define SLCR_A9_CPU_RST			0x1 + +#define SLCR_A9_CPU_RST_CTRL		0x244 /* CPU Software Reset Control */ +#define SLCR_REBOOT_STATUS		0x258 /* PS Reboot Status */ + +void __iomem *zynq_slcr_base; + +/** + * zynq_slcr_system_reset - Reset the entire system. + */ +void zynq_slcr_system_reset(void) +{ +	u32 reboot; + +	/* +	 * Unlock the SLCR then reset the system. +	 * Note that this seems to require raw i/o +	 * functions or there's a lockup? +	 */ +	writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK); + +	/* +	 * Clear 0x0F000000 bits of reboot status register to workaround +	 * the FSBL not loading the bitstream after soft-reboot +	 * This is a temporary solution until we know more. +	 */ +	reboot = readl(zynq_slcr_base + SLCR_REBOOT_STATUS); +	writel(reboot & 0xF0FFFFFF, zynq_slcr_base + SLCR_REBOOT_STATUS); +	writel(1, zynq_slcr_base + SLCR_PS_RST_CTRL_OFFSET); +} + +/** + * zynq_slcr_cpu_start - Start cpu + * @cpu:	cpu number + */ +void zynq_slcr_cpu_start(int cpu) +{ +	/* enable CPUn */ +	writel(SLCR_A9_CPU_CLKSTOP << cpu, +	       zynq_slcr_base + SLCR_A9_CPU_RST_CTRL); +	/* enable CLK for CPUn */ +	writel(0x0 << cpu, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL); +} + +/** + * zynq_slcr_cpu_stop - Stop cpu + * @cpu:	cpu number + */ +void zynq_slcr_cpu_stop(int cpu) +{ +	/* stop CLK and reset CPUn */ +	writel((SLCR_A9_CPU_CLKSTOP | SLCR_A9_CPU_RST) << cpu, +	       zynq_slcr_base + SLCR_A9_CPU_RST_CTRL); +} + +/** + * zynq_slcr_init + * Returns 0 on success, negative errno otherwise. + * + * Called early during boot from platform code to remap SLCR area. + */ +int __init zynq_slcr_init(void) +{ +	struct device_node *np; + +	np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr"); +	if (!np) { +		pr_err("%s: no slcr node found\n", __func__); +		BUG(); +	} + +	zynq_slcr_base = of_iomap(np, 0); +	if (!zynq_slcr_base) { +		pr_err("%s: Unable to map I/O memory\n", __func__); +		BUG(); +	} + +	/* unlock the SLCR so that registers can be changed */ +	writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK); + +	pr_info("%s mapped to %p\n", np->name, zynq_slcr_base); + +	xilinx_zynq_clocks_init(zynq_slcr_base); + +	of_node_put(np); + +	return 0; +} diff --git a/arch/arm/plat-orion/Makefile b/arch/arm/plat-orion/Makefile index ad97400ba3a..2eca54b6590 100644 --- a/arch/arm/plat-orion/Makefile +++ b/arch/arm/plat-orion/Makefile @@ -3,12 +3,6 @@  #  ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include -obj-$(CONFIG_ARCH_MVEBU)          += addr-map.o -obj-$(CONFIG_ARCH_KIRKWOOD)       += addr-map.o -obj-$(CONFIG_ARCH_DOVE)           += addr-map.o -obj-$(CONFIG_ARCH_ORION5X)        += addr-map.o -obj-$(CONFIG_ARCH_MV78XX0)        += addr-map.o -  orion-gpio-$(CONFIG_GENERIC_GPIO) += gpio.o  obj-$(CONFIG_PLAT_ORION_LEGACY)   += irq.o pcie.o time.o common.o mpp.o  obj-$(CONFIG_PLAT_ORION_LEGACY)   += $(orion-gpio-y) diff --git a/arch/arm/plat-orion/addr-map.c b/arch/arm/plat-orion/addr-map.c deleted file mode 100644 index 807ac8e5cbc..00000000000 --- a/arch/arm/plat-orion/addr-map.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * arch/arm/plat-orion/addr-map.c - * - * Address map functions for Marvell Orion based SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/mbus.h> -#include <linux/io.h> -#include <plat/addr-map.h> - -struct mbus_dram_target_info orion_mbus_dram_info; - -const struct mbus_dram_target_info *mv_mbus_dram_info(void) -{ -	return &orion_mbus_dram_info; -} -EXPORT_SYMBOL_GPL(mv_mbus_dram_info); - -/* - * DDR target is the same on all Orion platforms. - */ -#define TARGET_DDR		0 - -/* - * Helpers to get DDR bank info - */ -#define DDR_BASE_CS_OFF(n)	(0x0000 + ((n) << 3)) -#define DDR_SIZE_CS_OFF(n)	(0x0004 + ((n) << 3)) - -/* - * CPU Address Decode Windows registers - */ -#define WIN_CTRL_OFF		0x0000 -#define WIN_BASE_OFF		0x0004 -#define WIN_REMAP_LO_OFF	0x0008 -#define WIN_REMAP_HI_OFF	0x000c - -#define ATTR_HW_COHERENCY	(0x1 << 4) - -/* - * Default implementation - */ -static void __init __iomem * -orion_win_cfg_base(const struct orion_addr_map_cfg *cfg, int win) -{ -	return cfg->bridge_virt_base + (win << 4); -} - -/* - * Default implementation - */ -static int __init orion_cpu_win_can_remap(const struct orion_addr_map_cfg *cfg, -					  const int win) -{ -	if (win < cfg->remappable_wins) -		return 1; - -	return 0; -} - -void __init orion_setup_cpu_win(const struct orion_addr_map_cfg *cfg, -				const int win, const u32 base, -				const u32 size, const u8 target, -				const u8 attr, const int remap) -{ -	void __iomem *addr = cfg->win_cfg_base(cfg, win); -	u32 ctrl, base_high, remap_addr; - -	if (win >= cfg->num_wins) { -		printk(KERN_ERR "setup_cpu_win: trying to allocate window " -		       "%d when only %d allowed\n", win, cfg->num_wins); -	} - -	base_high = base & 0xffff0000; -	ctrl = ((size - 1) & 0xffff0000) | (attr << 8) | (target << 4) | 1; - -	writel(base_high, addr + WIN_BASE_OFF); -	writel(ctrl, addr + WIN_CTRL_OFF); -	if (cfg->cpu_win_can_remap(cfg, win)) { -		if (remap < 0) -			remap_addr = base; -		else -			remap_addr = remap; -		writel(remap_addr & 0xffff0000, addr + WIN_REMAP_LO_OFF); -		writel(0, addr + WIN_REMAP_HI_OFF); -	} -} - -/* - * Configure a number of windows. - */ -static void __init orion_setup_cpu_wins(const struct orion_addr_map_cfg * cfg, -					const struct orion_addr_map_info *info) -{ -	while (info->win != -1) { -		orion_setup_cpu_win(cfg, info->win, info->base, info->size, -				    info->target, info->attr, info->remap); -		info++; -	} -} - -static void __init orion_disable_wins(const struct orion_addr_map_cfg * cfg) -{ -	void __iomem *addr; -	int i; - -	for (i = 0; i < cfg->num_wins; i++) { -		addr = cfg->win_cfg_base(cfg, i); - -		writel(0, addr + WIN_BASE_OFF); -		writel(0, addr + WIN_CTRL_OFF); -		if (cfg->cpu_win_can_remap(cfg, i)) { -			writel(0, addr + WIN_REMAP_LO_OFF); -			writel(0, addr + WIN_REMAP_HI_OFF); -		} -	} -} - -/* - * Disable, clear and configure windows. - */ -void __init orion_config_wins(struct orion_addr_map_cfg * cfg, -			      const struct orion_addr_map_info *info) -{ -	if (!cfg->cpu_win_can_remap) -		cfg->cpu_win_can_remap = orion_cpu_win_can_remap; - -	if (!cfg->win_cfg_base) -		cfg->win_cfg_base = orion_win_cfg_base; - -	orion_disable_wins(cfg); - -	if (info) -		orion_setup_cpu_wins(cfg, info); -} - -/* - * Setup MBUS dram target info. - */ -void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg, -					const void __iomem *ddr_window_cpu_base) -{ -	int i; -	int cs; - -	orion_mbus_dram_info.mbus_dram_target_id = TARGET_DDR; - -	for (i = 0, cs = 0; i < 4; i++) { -		u32 base = readl(ddr_window_cpu_base + DDR_BASE_CS_OFF(i)); -		u32 size = readl(ddr_window_cpu_base + DDR_SIZE_CS_OFF(i)); - -		/* -		 * 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). -		 */ -		if ((size & 1) && !(base & 0xF)) { -			struct mbus_dram_window *w; - -			w = &orion_mbus_dram_info.cs[cs++]; -			w->cs_index = i; -			w->mbus_attr = 0xf & ~(1 << i); -			if (cfg->hw_io_coherency) -				w->mbus_attr |= ATTR_HW_COHERENCY; -			w->base = base & 0xffff0000; -			w->size = (size | 0x0000ffff) + 1; -		} -	} -	orion_mbus_dram_info.num_cs = cs; -} diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index c29ee7ea200..e39c2ba6e2f 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c @@ -439,6 +439,64 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)  	}  } +#ifdef CONFIG_DEBUG_FS +#include <linux/seq_file.h> + +static void orion_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ +	struct orion_gpio_chip *ochip = +		container_of(chip, struct orion_gpio_chip, chip); +	u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk; +	int i; + +	out	= readl_relaxed(GPIO_OUT(ochip)); +	io_conf	= readl_relaxed(GPIO_IO_CONF(ochip)); +	blink	= readl_relaxed(GPIO_BLINK_EN(ochip)); +	in_pol	= readl_relaxed(GPIO_IN_POL(ochip)); +	data_in	= readl_relaxed(GPIO_DATA_IN(ochip)); +	cause	= readl_relaxed(GPIO_EDGE_CAUSE(ochip)); +	edg_msk	= readl_relaxed(GPIO_EDGE_MASK(ochip)); +	lvl_msk	= readl_relaxed(GPIO_LEVEL_MASK(ochip)); + +	for (i = 0; i < chip->ngpio; i++) { +		const char *label; +		u32 msk; +		bool is_out; + +		label = gpiochip_is_requested(chip, i); +		if (!label) +			continue; + +		msk = 1 << i; +		is_out = !(io_conf & msk); + +		seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label); + +		if (is_out) { +			seq_printf(s, " out %s %s\n", +				   out & msk ? "hi" : "lo", +				   blink & msk ? "(blink )" : ""); +			continue; +		} + +		seq_printf(s, " in  %s (act %s) - IRQ", +			   (data_in ^ in_pol) & msk  ? "hi" : "lo", +			   in_pol & msk ? "lo" : "hi"); +		if (!((edg_msk | lvl_msk) & msk)) { +			seq_printf(s, " disabled\n"); +			continue; +		} +		if (edg_msk & msk) +			seq_printf(s, " edge "); +		if (lvl_msk & msk) +			seq_printf(s, " level"); +		seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear  "); +	} +} +#else +#define orion_gpio_dbg_show NULL +#endif +  void __init orion_gpio_init(struct device_node *np,  			    int gpio_base, int ngpio,  			    void __iomem *base, int mask_offset, @@ -471,6 +529,7 @@ void __init orion_gpio_init(struct device_node *np,  #ifdef CONFIG_OF  	ochip->chip.of_node = np;  #endif +	ochip->chip.dbg_show = orion_gpio_dbg_show;  	spin_lock_init(&ochip->lock);  	ochip->base = (void __iomem *)base; diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 0f51ed687dc..b05ecab915c 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -4,6 +4,13 @@  menu "Bus devices" +config MVEBU_MBUS +	bool +	depends on PLAT_ORION +	help +	  Driver needed for the MBus configuration on Marvell EBU SoCs +	  (Kirkwood, Dove, Orion5x, MV78XX0 and Armada 370/XP). +  config OMAP_OCP2SCP  	tristate "OMAP OCP2SCP DRIVER"  	depends on ARCH_OMAP2PLUS diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 45d997c8545..3c7b53c1209 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -2,6 +2,7 @@  # Makefile for the bus drivers.  # +obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o  obj-$(CONFIG_OMAP_OCP2SCP)	+= omap-ocp2scp.o  # Interconnect bus driver for OMAP SoCs. diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c new file mode 100644 index 00000000000..8740f46b4d0 --- /dev/null +++ b/drivers/bus/mvebu-mbus.c @@ -0,0 +1,870 @@ +/* + * Address map functions for Marvell EBU SoCs (Kirkwood, Armada + * 370/XP, Dove, Orion5x and MV78xx0) + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * The Marvell EBU SoCs have a configurable physical address space: + * the physical address at which certain devices (PCIe, NOR, NAND, + * etc.) sit can be configured. The configuration takes place through + * two sets of registers: + * + * - One to configure the access of the CPU to the devices. Depending + *   on the families, there are between 8 and 20 configurable windows, + *   each can be use to create a physical memory window that maps to a + *   specific device. Devices are identified by a tuple (target, + *   attribute). + * + * - One to configure the access to the CPU to the SDRAM. There are + *   either 2 (for Dove) or 4 (for other families) windows to map the + *   SDRAM into the physical address space. + * + * This driver: + * + * - Reads out the SDRAM address decoding windows at initialization + *   time, and fills the mvebu_mbus_dram_info structure with these + *   informations. The exported function mv_mbus_dram_info() allow + *   device drivers to get those informations related to the SDRAM + *   address decoding windows. This is because devices also have their + *   own windows (configured through registers that are part of each + *   device register space), and therefore the drivers for Marvell + *   devices have to configure those device -> SDRAM windows to ensure + *   that DMA works properly. + * + * - Provides an API for platform code or device drivers to + *   dynamically add or remove address decoding windows for the CPU -> + *   device accesses. This API is mvebu_mbus_add_window(), + *   mvebu_mbus_add_window_remap_flags() and + *   mvebu_mbus_del_window(). Since the (target, attribute) values + *   differ from one SoC family to another, the API uses a 'const char + *   *' string to identify devices, and this driver is responsible for + *   knowing the mapping between the name of a device and its + *   corresponding (target, attribute) in the current SoC family. + * + * - Provides a debugfs interface in /sys/kernel/debug/mvebu-mbus/ to + *   see the list of CPU -> SDRAM windows and their configuration + *   (file 'sdram') and the list of CPU -> devices windows and their + *   configuration (file 'devices'). + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/mbus.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/debugfs.h> + +/* + * DDR target is the same on all platforms. + */ +#define TARGET_DDR		0 + +/* + * CPU Address Decode Windows registers + */ +#define WIN_CTRL_OFF		0x0000 +#define   WIN_CTRL_ENABLE       BIT(0) +#define   WIN_CTRL_TGT_MASK     0xf0 +#define   WIN_CTRL_TGT_SHIFT    4 +#define   WIN_CTRL_ATTR_MASK    0xff00 +#define   WIN_CTRL_ATTR_SHIFT   8 +#define   WIN_CTRL_SIZE_MASK    0xffff0000 +#define   WIN_CTRL_SIZE_SHIFT   16 +#define WIN_BASE_OFF		0x0004 +#define   WIN_BASE_LOW          0xffff0000 +#define   WIN_BASE_HIGH         0xf +#define WIN_REMAP_LO_OFF	0x0008 +#define   WIN_REMAP_LOW         0xffff0000 +#define WIN_REMAP_HI_OFF	0x000c + +#define ATTR_HW_COHERENCY	(0x1 << 4) + +#define DDR_BASE_CS_OFF(n)	(0x0000 + ((n) << 3)) +#define  DDR_BASE_CS_HIGH_MASK  0xf +#define  DDR_BASE_CS_LOW_MASK   0xff000000 +#define DDR_SIZE_CS_OFF(n)	(0x0004 + ((n) << 3)) +#define  DDR_SIZE_ENABLED       BIT(0) +#define  DDR_SIZE_CS_MASK       0x1c +#define  DDR_SIZE_CS_SHIFT      2 +#define  DDR_SIZE_MASK          0xff000000 + +#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4) + +struct mvebu_mbus_mapping { +	const char *name; +	u8 target; +	u8 attr; +	u8 attrmask; +}; + +/* + * Masks used for the 'attrmask' field of mvebu_mbus_mapping. They + * allow to get the real attribute value, discarding the special bits + * used to select a PCI MEM region or a PCI WA region. This allows the + * debugfs code to reverse-match the name of a device from its + * target/attr values. + * + * For all devices except PCI, all bits of 'attr' must be + * considered. For most SoCs, only bit 3 should be ignored (it allows + * to select between PCI MEM and PCI I/O). On Orion5x however, there + * is the special bit 5 to select a PCI WA region. + */ +#define MAPDEF_NOMASK       0xff +#define MAPDEF_PCIMASK      0xf7 +#define MAPDEF_ORIONPCIMASK 0xd7 + +/* Macro used to define one mvebu_mbus_mapping entry */ +#define MAPDEF(__n, __t, __a, __m) \ +	{ .name = __n, .target = __t, .attr = __a, .attrmask = __m } + +struct mvebu_mbus_state; + +struct mvebu_mbus_soc_data { +	unsigned int num_wins; +	unsigned int num_remappable_wins; +	unsigned int (*win_cfg_offset)(const int win); +	void (*setup_cpu_target)(struct mvebu_mbus_state *s); +	int (*show_cpu_target)(struct mvebu_mbus_state *s, +			       struct seq_file *seq, void *v); +	const struct mvebu_mbus_mapping *map; +}; + +struct mvebu_mbus_state { +	void __iomem *mbuswins_base; +	void __iomem *sdramwins_base; +	struct dentry *debugfs_root; +	struct dentry *debugfs_sdram; +	struct dentry *debugfs_devs; +	const struct mvebu_mbus_soc_data *soc; +	int hw_io_coherency; +}; + +static struct mvebu_mbus_state mbus_state; + +static struct mbus_dram_target_info mvebu_mbus_dram_info; +const struct mbus_dram_target_info *mv_mbus_dram_info(void) +{ +	return &mvebu_mbus_dram_info; +} +EXPORT_SYMBOL_GPL(mv_mbus_dram_info); + +/* + * Functions to manipulate the address decoding windows + */ + +static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus, +				   int win, int *enabled, u64 *base, +				   u32 *size, u8 *target, u8 *attr, +				   u64 *remap) +{ +	void __iomem *addr = mbus->mbuswins_base + +		mbus->soc->win_cfg_offset(win); +	u32 basereg = readl(addr + WIN_BASE_OFF); +	u32 ctrlreg = readl(addr + WIN_CTRL_OFF); + +	if (!(ctrlreg & WIN_CTRL_ENABLE)) { +		*enabled = 0; +		return; +	} + +	*enabled = 1; +	*base = ((u64)basereg & WIN_BASE_HIGH) << 32; +	*base |= (basereg & WIN_BASE_LOW); +	*size = (ctrlreg | ~WIN_CTRL_SIZE_MASK) + 1; + +	if (target) +		*target = (ctrlreg & WIN_CTRL_TGT_MASK) >> WIN_CTRL_TGT_SHIFT; + +	if (attr) +		*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); +			*remap = ((u64)remap_hi << 32) | remap_low; +		} else +			*remap = 0; +	} +} + +static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus, +				      int win) +{ +	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) { +		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); +} + +/* + * Checks whether the given (base, base+size) area doesn't overlap an + * existing region + */ +static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus, +				       phys_addr_t base, size_t size, +				       u8 target, u8 attr) +{ +	u64 end = (u64)base + size; +	int win; + +	for (win = 0; win < mbus->soc->num_wins; win++) { +		u64 wbase, wend; +		u32 wsize; +		u8 wtarget, wattr; +		int enabled; + +		mvebu_mbus_read_window(mbus, win, +				       &enabled, &wbase, &wsize, +				       &wtarget, &wattr, NULL); + +		if (!enabled) +			continue; + +		wend = wbase + wsize; + +		/* +		 * Check if the current window overlaps with the +		 * proposed physical range +		 */ +		if ((u64)base < wend && end > wbase) +			return 0; + +		/* +		 * Check if target/attribute conflicts +		 */ +		if (target == wtarget && attr == wattr) +			return 0; +	} + +	return 1; +} + +static int mvebu_mbus_find_window(struct mvebu_mbus_state *mbus, +				  phys_addr_t base, size_t size) +{ +	int win; + +	for (win = 0; win < mbus->soc->num_wins; win++) { +		u64 wbase; +		u32 wsize; +		int enabled; + +		mvebu_mbus_read_window(mbus, win, +				       &enabled, &wbase, &wsize, +				       NULL, NULL, NULL); + +		if (!enabled) +			continue; + +		if (base == wbase && size == wsize) +			return win; +	} + +	return -ENODEV; +} + +static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus, +				   int win, phys_addr_t base, size_t size, +				   phys_addr_t remap, u8 target, +				   u8 attr) +{ +	void __iomem *addr = mbus->mbuswins_base + +		mbus->soc->win_cfg_offset(win); +	u32 ctrl, remap_addr; + +	ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) | +		(attr << WIN_CTRL_ATTR_SHIFT)    | +		(target << WIN_CTRL_TGT_SHIFT)   | +		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 (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); +	} + +	return 0; +} + +static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus, +				   phys_addr_t base, size_t size, +				   phys_addr_t remap, u8 target, +				   u8 attr) +{ +	int win; + +	if (remap == MVEBU_MBUS_NO_REMAP) { +		for (win = mbus->soc->num_remappable_wins; +		     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); +	} + + +	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; +} + +/* + * Debugfs debugging + */ + +/* Common function used for Dove, Kirkwood, Armada 370/XP and Orion 5x */ +static int mvebu_sdram_debug_show_orion(struct mvebu_mbus_state *mbus, +					struct seq_file *seq, void *v) +{ +	int i; + +	for (i = 0; i < 4; i++) { +		u32 basereg = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i)); +		u32 sizereg = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i)); +		u64 base; +		u32 size; + +		if (!(sizereg & DDR_SIZE_ENABLED)) { +			seq_printf(seq, "[%d] disabled\n", i); +			continue; +		} + +		base = ((u64)basereg & DDR_BASE_CS_HIGH_MASK) << 32; +		base |= basereg & DDR_BASE_CS_LOW_MASK; +		size = (sizereg | ~DDR_SIZE_MASK); + +		seq_printf(seq, "[%d] %016llx - %016llx : cs%d\n", +			   i, (unsigned long long)base, +			   (unsigned long long)base + size + 1, +			   (sizereg & DDR_SIZE_CS_MASK) >> DDR_SIZE_CS_SHIFT); +	} + +	return 0; +} + +/* Special function for Dove */ +static int mvebu_sdram_debug_show_dove(struct mvebu_mbus_state *mbus, +				       struct seq_file *seq, void *v) +{ +	int i; + +	for (i = 0; i < 2; i++) { +		u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i)); +		u64 base; +		u32 size; + +		if (!(map & 1)) { +			seq_printf(seq, "[%d] disabled\n", i); +			continue; +		} + +		base = map & 0xff800000; +		size = 0x100000 << (((map & 0x000f0000) >> 16) - 4); + +		seq_printf(seq, "[%d] %016llx - %016llx : cs%d\n", +			   i, (unsigned long long)base, +			   (unsigned long long)base + size, i); +	} + +	return 0; +} + +static int mvebu_sdram_debug_show(struct seq_file *seq, void *v) +{ +	struct mvebu_mbus_state *mbus = &mbus_state; +	return mbus->soc->show_cpu_target(mbus, seq, v); +} + +static int mvebu_sdram_debug_open(struct inode *inode, struct file *file) +{ +	return single_open(file, mvebu_sdram_debug_show, inode->i_private); +} + +static const struct file_operations mvebu_sdram_debug_fops = { +	.open = mvebu_sdram_debug_open, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = single_release, +}; + +static int mvebu_devs_debug_show(struct seq_file *seq, void *v) +{ +	struct mvebu_mbus_state *mbus = &mbus_state; +	int win; + +	for (win = 0; win < mbus->soc->num_wins; win++) { +		u64 wbase, wremap; +		u32 wsize; +		u8 wtarget, wattr; +		int enabled, i; +		const char *name; + +		mvebu_mbus_read_window(mbus, win, +				       &enabled, &wbase, &wsize, +				       &wtarget, &wattr, &wremap); + +		if (!enabled) { +			seq_printf(seq, "[%02d] disabled\n", win); +			continue; +		} + + +		for (i = 0; mbus->soc->map[i].name; i++) +			if (mbus->soc->map[i].target == wtarget && +			    mbus->soc->map[i].attr == +			    (wattr & mbus->soc->map[i].attrmask)) +				break; + +		name = mbus->soc->map[i].name ?: "unknown"; + +		seq_printf(seq, "[%02d] %016llx - %016llx : %s", +			   win, (unsigned long long)wbase, +			   (unsigned long long)(wbase + wsize), name); + +		if (win < mbus->soc->num_remappable_wins) { +			seq_printf(seq, " (remap %016llx)\n", +				   (unsigned long long)wremap); +		} else +			seq_printf(seq, "\n"); +	} + +	return 0; +} + +static int mvebu_devs_debug_open(struct inode *inode, struct file *file) +{ +	return single_open(file, mvebu_devs_debug_show, inode->i_private); +} + +static const struct file_operations mvebu_devs_debug_fops = { +	.open = mvebu_devs_debug_open, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = single_release, +}; + +/* + * SoC-specific functions and definitions + */ + +static unsigned int orion_mbus_win_offset(int win) +{ +	return win << 4; +} + +static unsigned int armada_370_xp_mbus_win_offset(int win) +{ +	/* The register layout is a bit annoying and the below code +	 * tries to cope with it. +	 * - At offset 0x0, there are the registers for the first 8 +	 *   windows, with 4 registers of 32 bits per window (ctrl, +	 *   base, remap low, remap high) +	 * - Then at offset 0x80, there is a hole of 0x10 bytes for +	 *   the internal registers base address and internal units +	 *   sync barrier register. +	 * - Then at offset 0x90, there the registers for 12 +	 *   windows, with only 2 registers of 32 bits per window +	 *   (ctrl, base). +	 */ +	if (win < 8) +		return win << 4; +	else +		return 0x90 + ((win - 8) << 3); +} + +static unsigned int mv78xx0_mbus_win_offset(int win) +{ +	if (win < 8) +		return win << 4; +	else +		return 0x900 + ((win - 8) << 4); +} + +static void __init +mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) +{ +	int i; +	int cs; + +	mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR; + +	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)); + +		/* +		 * 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). +		 */ +		if ((size & DDR_SIZE_ENABLED) && +		    !(base & DDR_BASE_CS_HIGH_MASK)) { +			struct mbus_dram_window *w; + +			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; +		} +	} +	mvebu_mbus_dram_info.num_cs = cs; +} + +static void __init +mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) +{ +	int i; +	int cs; + +	mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR; + +	for (i = 0, cs = 0; i < 2; i++) { +		u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i)); + +		/* +		 * Chip select enabled? +		 */ +		if (map & 1) { +			struct mbus_dram_window *w; + +			w = &mvebu_mbus_dram_info.cs[cs++]; +			w->cs_index = i; +			w->mbus_attr = 0; /* CS address decoding done inside */ +					  /* the DDR controller, no need to  */ +					  /* provide attributes */ +			w->base = map & 0xff800000; +			w->size = 0x100000 << (((map & 0x000f0000) >> 16) - 4); +		} +	} + +	mvebu_mbus_dram_info.num_cs = cs; +} + +static const struct mvebu_mbus_mapping armada_370_map[] = { +	MAPDEF("bootrom",     1, 0xe0, MAPDEF_NOMASK), +	MAPDEF("devbus-boot", 1, 0x2f, MAPDEF_NOMASK), +	MAPDEF("devbus-cs0",  1, 0x3e, MAPDEF_NOMASK), +	MAPDEF("devbus-cs1",  1, 0x3d, MAPDEF_NOMASK), +	MAPDEF("devbus-cs2",  1, 0x3b, MAPDEF_NOMASK), +	MAPDEF("devbus-cs3",  1, 0x37, MAPDEF_NOMASK), +	MAPDEF("pcie0.0",     4, 0xe0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.0",     8, 0xe0, MAPDEF_PCIMASK), +	{}, +}; + +static const struct mvebu_mbus_soc_data armada_370_mbus_data = { +	.num_wins            = 20, +	.num_remappable_wins = 8, +	.win_cfg_offset      = armada_370_xp_mbus_win_offset, +	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target, +	.show_cpu_target     = mvebu_sdram_debug_show_orion, +	.map                 = armada_370_map, +}; + +static const struct mvebu_mbus_mapping armada_xp_map[] = { +	MAPDEF("bootrom",     1, 0x1d, MAPDEF_NOMASK), +	MAPDEF("devbus-boot", 1, 0x2f, MAPDEF_NOMASK), +	MAPDEF("devbus-cs0",  1, 0x3e, MAPDEF_NOMASK), +	MAPDEF("devbus-cs1",  1, 0x3d, MAPDEF_NOMASK), +	MAPDEF("devbus-cs2",  1, 0x3b, MAPDEF_NOMASK), +	MAPDEF("devbus-cs3",  1, 0x37, MAPDEF_NOMASK), +	MAPDEF("pcie0.0",     4, 0xe0, MAPDEF_PCIMASK), +	MAPDEF("pcie0.1",     4, 0xd0, MAPDEF_PCIMASK), +	MAPDEF("pcie0.2",     4, 0xb0, MAPDEF_PCIMASK), +	MAPDEF("pcie0.3",     4, 0x70, MAPDEF_PCIMASK), +	MAPDEF("pcie1.0",     8, 0xe0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.1",     8, 0xd0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.2",     8, 0xb0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.3",     8, 0x70, MAPDEF_PCIMASK), +	MAPDEF("pcie2.0",     4, 0xf0, MAPDEF_PCIMASK), +	MAPDEF("pcie3.0",     8, 0xf0, MAPDEF_PCIMASK), +	{}, +}; + +static const struct mvebu_mbus_soc_data armada_xp_mbus_data = { +	.num_wins            = 20, +	.num_remappable_wins = 8, +	.win_cfg_offset      = armada_370_xp_mbus_win_offset, +	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target, +	.show_cpu_target     = mvebu_sdram_debug_show_orion, +	.map                 = armada_xp_map, +}; + +static const struct mvebu_mbus_mapping kirkwood_map[] = { +	MAPDEF("pcie0.0", 4, 0xe0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.0", 4, 0xd0, MAPDEF_PCIMASK), +	MAPDEF("sram",    3, 0x01, MAPDEF_NOMASK), +	MAPDEF("nand",    1, 0x2f, MAPDEF_NOMASK), +	{}, +}; + +static const struct mvebu_mbus_soc_data kirkwood_mbus_data = { +	.num_wins            = 8, +	.num_remappable_wins = 4, +	.win_cfg_offset      = orion_mbus_win_offset, +	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target, +	.show_cpu_target     = mvebu_sdram_debug_show_orion, +	.map                 = kirkwood_map, +}; + +static const struct mvebu_mbus_mapping dove_map[] = { +	MAPDEF("pcie0.0",    0x4, 0xe0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.0",    0x8, 0xe0, MAPDEF_PCIMASK), +	MAPDEF("cesa",       0x3, 0x01, MAPDEF_NOMASK), +	MAPDEF("bootrom",    0x1, 0xfd, MAPDEF_NOMASK), +	MAPDEF("scratchpad", 0xd, 0x0, MAPDEF_NOMASK), +	{}, +}; + +static const struct mvebu_mbus_soc_data dove_mbus_data = { +	.num_wins            = 8, +	.num_remappable_wins = 4, +	.win_cfg_offset      = orion_mbus_win_offset, +	.setup_cpu_target    = mvebu_mbus_dove_setup_cpu_target, +	.show_cpu_target     = mvebu_sdram_debug_show_dove, +	.map                 = dove_map, +}; + +static const struct mvebu_mbus_mapping orion5x_map[] = { +	MAPDEF("pcie0.0",     4, 0x51, MAPDEF_ORIONPCIMASK), +	MAPDEF("pci0.0",      3, 0x51, MAPDEF_ORIONPCIMASK), +	MAPDEF("devbus-boot", 1, 0x0f, MAPDEF_NOMASK), +	MAPDEF("devbus-cs0",  1, 0x1e, MAPDEF_NOMASK), +	MAPDEF("devbus-cs1",  1, 0x1d, MAPDEF_NOMASK), +	MAPDEF("devbus-cs2",  1, 0x1b, MAPDEF_NOMASK), +	MAPDEF("sram",        0, 0x00, MAPDEF_NOMASK), +	{}, +}; + +/* + * Some variants of Orion5x have 4 remappable windows, some other have + * only two of them. + */ +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, +	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target, +	.show_cpu_target     = mvebu_sdram_debug_show_orion, +	.map                 = orion5x_map, +}; + +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, +	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target, +	.show_cpu_target     = mvebu_sdram_debug_show_orion, +	.map                 = orion5x_map, +}; + +static const struct mvebu_mbus_mapping mv78xx0_map[] = { +	MAPDEF("pcie0.0", 4, 0xe0, MAPDEF_PCIMASK), +	MAPDEF("pcie0.1", 4, 0xd0, MAPDEF_PCIMASK), +	MAPDEF("pcie0.2", 4, 0xb0, MAPDEF_PCIMASK), +	MAPDEF("pcie0.3", 4, 0x70, MAPDEF_PCIMASK), +	MAPDEF("pcie1.0", 8, 0xe0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.1", 8, 0xd0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.2", 8, 0xb0, MAPDEF_PCIMASK), +	MAPDEF("pcie1.3", 8, 0x70, MAPDEF_PCIMASK), +	MAPDEF("pcie2.0", 4, 0xf0, MAPDEF_PCIMASK), +	MAPDEF("pcie3.0", 8, 0xf0, MAPDEF_PCIMASK), +	{}, +}; + +static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = { +	.num_wins            = 14, +	.num_remappable_wins = 8, +	.win_cfg_offset      = mv78xx0_mbus_win_offset, +	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target, +	.show_cpu_target     = mvebu_sdram_debug_show_orion, +	.map                 = mv78xx0_map, +}; + +/* + * The driver doesn't yet have a DT binding because the details of + * this DT binding still need to be sorted out. However, as a + * preparation, we already use of_device_id to match a SoC description + * string against the SoC specific details of this driver. + */ +static const struct of_device_id of_mvebu_mbus_ids[] = { +	{ .compatible = "marvell,armada370-mbus", +	  .data = &armada_370_mbus_data, }, +	{ .compatible = "marvell,armadaxp-mbus", +	  .data = &armada_xp_mbus_data, }, +	{ .compatible = "marvell,kirkwood-mbus", +	  .data = &kirkwood_mbus_data, }, +	{ .compatible = "marvell,dove-mbus", +	  .data = &dove_mbus_data, }, +	{ .compatible = "marvell,orion5x-88f5281-mbus", +	  .data = &orion5x_4win_mbus_data, }, +	{ .compatible = "marvell,orion5x-88f5182-mbus", +	  .data = &orion5x_2win_mbus_data, }, +	{ .compatible = "marvell,orion5x-88f5181-mbus", +	  .data = &orion5x_2win_mbus_data, }, +	{ .compatible = "marvell,orion5x-88f6183-mbus", +	  .data = &orion5x_4win_mbus_data, }, +	{ .compatible = "marvell,mv78xx0-mbus", +	  .data = &mv78xx0_mbus_data, }, +	{ }, +}; + +/* + * Public API of the driver + */ +int mvebu_mbus_add_window_remap_flags(const char *devname, phys_addr_t base, +				      size_t size, phys_addr_t remap, +				      unsigned int flags) +{ +	struct mvebu_mbus_state *s = &mbus_state; +	u8 target, attr; +	int i; + +	if (!s->soc->map) +		return -ENODEV; + +	for (i = 0; s->soc->map[i].name; i++) +		if (!strcmp(s->soc->map[i].name, devname)) +			break; + +	if (!s->soc->map[i].name) { +		pr_err("mvebu-mbus: unknown device '%s'\n", devname); +		return -ENODEV; +	} + +	target = s->soc->map[i].target; +	attr   = s->soc->map[i].attr; + +	if (flags == MVEBU_MBUS_PCI_MEM) +		attr |= 0x8; +	else if (flags == MVEBU_MBUS_PCI_WA) +		attr |= 0x28; + +	if (!mvebu_mbus_window_conflicts(s, base, size, target, attr)) { +		pr_err("mvebu-mbus: cannot add window '%s', conflicts with another window\n", +		       devname); +		return -EINVAL; +	} + +	return mvebu_mbus_alloc_window(s, base, size, remap, target, attr); + +} + +int mvebu_mbus_add_window(const char *devname, phys_addr_t base, size_t size) +{ +	return mvebu_mbus_add_window_remap_flags(devname, base, size, +						 MVEBU_MBUS_NO_REMAP, 0); +} + +int mvebu_mbus_del_window(phys_addr_t base, size_t size) +{ +	int win; + +	win = mvebu_mbus_find_window(&mbus_state, base, size); +	if (win < 0) +		return win; + +	mvebu_mbus_disable_window(&mbus_state, win); +	return 0; +} + +static __init int mvebu_mbus_debugfs_init(void) +{ +	struct mvebu_mbus_state *s = &mbus_state; + +	/* +	 * If no base has been initialized, doesn't make sense to +	 * register the debugfs entries. We may be on a multiplatform +	 * kernel that isn't running a Marvell EBU SoC. +	 */ +	if (!s->mbuswins_base) +		return 0; + +	s->debugfs_root = debugfs_create_dir("mvebu-mbus", NULL); +	if (s->debugfs_root) { +		s->debugfs_sdram = debugfs_create_file("sdram", S_IRUGO, +						       s->debugfs_root, NULL, +						       &mvebu_sdram_debug_fops); +		s->debugfs_devs = debugfs_create_file("devices", S_IRUGO, +						      s->debugfs_root, NULL, +						      &mvebu_devs_debug_fops); +	} + +	return 0; +} +fs_initcall(mvebu_mbus_debugfs_init); + +int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, +			   size_t mbuswins_size, +			   phys_addr_t sdramwins_phys_base, +			   size_t sdramwins_size) +{ +	struct mvebu_mbus_state *mbus = &mbus_state; +	const struct of_device_id *of_id; +	int win; + +	for (of_id = of_mvebu_mbus_ids; of_id->compatible; of_id++) +		if (!strcmp(of_id->compatible, soc)) +			break; + +	if (!of_id->compatible) { +		pr_err("mvebu-mbus: could not find a matching SoC family\n"); +		return -ENODEV; +	} + +	mbus->soc = of_id->data; + +	mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size); +	if (!mbus->mbuswins_base) +		return -ENOMEM; + +	mbus->sdramwins_base = ioremap(sdramwins_phys_base, sdramwins_size); +	if (!mbus->sdramwins_base) { +		iounmap(mbus_state.mbuswins_base); +		return -ENOMEM; +	} + +	if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric")) +		mbus->hw_io_coherency = 1; + +	for (win = 0; win < mbus->soc->num_wins; win++) +		mvebu_mbus_disable_window(mbus, win); + +	mbus->soc->setup_cpu_target(mbus); + +	return 0; +} diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c index 62dcdcdec94..791a6719d8a 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c @@ -2552,7 +2552,7 @@ static const char * const intc_groups[] = {  	"intc_irq2",  	"intc_irq2_b",  	"intc_irq3", -	"intc_irq4_b", +	"intc_irq3_b",  };  static const char * const lbsc_groups[] = { diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index 0880ef1a01b..0127601c26c 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c @@ -16,6 +16,7 @@  #include <linux/export.h>  #include <linux/types.h>  #include <linux/init.h> +#include <linux/reset.h>  #include <linux/platform_device.h>  #include <linux/err.h>  #include <linux/spinlock.h> @@ -661,7 +662,7 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)  }  EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel); -static int ipu_reset(struct ipu_soc *ipu) +static int ipu_memory_reset(struct ipu_soc *ipu)  {  	unsigned long timeout; @@ -1105,7 +1106,12 @@ static int ipu_probe(struct platform_device *pdev)  	if (ret)  		goto out_failed_irq; -	ret = ipu_reset(ipu); +	ret = device_reset(&pdev->dev); +	if (ret) { +		dev_err(&pdev->dev, "failed to reset: %d\n", ret); +		goto out_failed_reset; +	} +	ret = ipu_memory_reset(ipu);  	if (ret)  		goto out_failed_reset; @@ -1131,8 +1137,8 @@ static int ipu_probe(struct platform_device *pdev)  failed_add_clients:  	ipu_submodules_exit(ipu);  failed_submodules_init: -	ipu_irq_exit(ipu);  out_failed_reset: +	ipu_irq_exit(ipu);  out_failed_irq:  	clk_disable_unprepare(ipu->clk);  failed_clk_get: diff --git a/include/linux/mbus.h b/include/linux/mbus.h index efa1a6d7aca..dba482e31a1 100644 --- a/include/linux/mbus.h +++ b/include/linux/mbus.h @@ -32,6 +32,20 @@ struct mbus_dram_target_info  	} cs[4];  }; +/* Flags for PCI/PCIe address decoding regions */ +#define MVEBU_MBUS_PCI_IO  0x1 +#define MVEBU_MBUS_PCI_MEM 0x2 +#define MVEBU_MBUS_PCI_WA  0x3 + +/* + * Magic value that explicits that we don't need a remapping-capable + * address decoding window. + */ +#define MVEBU_MBUS_NO_REMAP (0xffffffff) + +/* Maximum size of a mbus window name */ +#define MVEBU_MBUS_MAX_WINNAME_SZ 32 +  /*   * The Marvell mbus is to be found only on SOCs from the Orion family   * at the moment.  Provide a dummy stub for other architectures. @@ -44,4 +58,15 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void)  	return NULL;  }  #endif -#endif + +int mvebu_mbus_add_window_remap_flags(const char *devname, phys_addr_t base, +				      size_t size, phys_addr_t remap, +				      unsigned int flags); +int mvebu_mbus_add_window(const char *devname, phys_addr_t base, +			  size_t size); +int mvebu_mbus_del_window(phys_addr_t base, size_t size); +int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base, +		    size_t mbus_size, phys_addr_t sdram_phys_base, +		    size_t sdram_size); + +#endif /* __LINUX_MBUS_H */  |