Commit fcba9145 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'soc-for-linus-3' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC platform updates (part 3) from Arnd Bergmann:
 "This is the third and smallest of the SoC specific updates.  Changes
  include:

   - SMP support for the Xilinx zynq platform
   - Smaller imx changes
   - LPAE support for mvebu
   - Moving the orion5x, kirkwood, dove and mvebu platforms to a common
     "mbus" driver for their internal devices.

  It would be good to get feedback on the location of the "mbus" driver.
  Since this is used on multiple platforms may potentially get shared
  with other architectures (powerpc and arm64), it was moved to
  drivers/bus/.  We expect other similar drivers to get moved to the
  same place in order to avoid creating more top-level directories under
  drivers/ or cluttering up the messy drivers/misc/ even more."

* tag 'soc-for-linus-3' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (50 commits)
  ARM: imx: reset_controller may be disabled
  ARM: mvebu: Align the internal registers virtual base to support LPAE
  ARM: mvebu: Limit the DMA zone when LPAE is selected
  arm: plat-orion: remove addr-map code
  arm: mach-mv78xx0: convert to use the mvebu-mbus driver
  arm: mach-orion5x: convert to use mvebu-mbus driver
  arm: mach-dove: convert to use mvebu-mbus driver
  arm: mach-kirkwood: convert to use mvebu-mbus driver
  arm: mach-mvebu: convert to use mvebu-mbus driver
  ARM i.MX53: set CLK_SET_RATE_PARENT flag on the tve_ext_sel clock
  ARM i.MX53: tve_di clock is not part of the CCM, but of TVE
  ARM i.MX53: make tve_ext_sel propagate rate change to PLL
  ARM i.MX53: Remove unused tve_gate clkdev entry
  ARM i.MX5: Remove tve_sel clock from i.MX53 clock tree
  ARM: i.MX5: Add PATA and SRTC clocks
  ARM: imx: do not bring up unavailable cores
  ARM: imx: add initial imx6dl support
  ARM: imx1: mm: add call to mxc_device_init
  ARM: imx_v4_v5_defconfig: Add CONFIG_GPIO_SYSFS
  ARM: imx_v6_v7_defconfig: Select CONFIG_PERF_EVENTS
  ...
parents a8c4b90e 5c5f0421
...@@ -38,7 +38,6 @@ clocks and IDs. ...@@ -38,7 +38,6 @@ clocks and IDs.
usb_phy_podf 23 usb_phy_podf 23
cpu_podf 24 cpu_podf 24
di_pred 25 di_pred 25
tve_di 26
tve_s 27 tve_s 27
uart1_ipg_gate 28 uart1_ipg_gate 28
uart1_per_gate 29 uart1_per_gate 29
...@@ -172,6 +171,19 @@ clocks and IDs. ...@@ -172,6 +171,19 @@ clocks and IDs.
can1_serial_gate 157 can1_serial_gate 157
can1_ipg_gate 158 can1_ipg_gate 158
owire_gate 159 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): Examples (for mx53):
......
...@@ -205,6 +205,9 @@ clocks and IDs. ...@@ -205,6 +205,9 @@ clocks and IDs.
enet_ref 190 enet_ref 190
usbphy1_gate 191 usbphy1_gate 191
usbphy2_gate 192 usbphy2_gate 192
pll4_post_div 193
pll5_post_div 194
pll5_video_div 195
Examples: Examples:
......
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
...@@ -8,6 +8,8 @@ Required properties: ...@@ -8,6 +8,8 @@ Required properties:
- interrupts: Should contain sync interrupt and error interrupt, - interrupts: Should contain sync interrupt and error interrupt,
in this order. in this order.
- #crtc-cells: 1, See below - #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: example:
...@@ -16,6 +18,7 @@ ipu: ipu@18000000 { ...@@ -16,6 +18,7 @@ ipu: ipu@18000000 {
compatible = "fsl,imx53-ipu"; compatible = "fsl,imx53-ipu";
reg = <0x18000000 0x080000000>; reg = <0x18000000 0x080000000>;
interrupts = <11 10>; interrupts = <11 10>;
resets = <&src 2>;
}; };
Parallel display support Parallel display support
......
...@@ -498,6 +498,7 @@ config ARCH_DOVE ...@@ -498,6 +498,7 @@ config ARCH_DOVE
select PINCTRL_DOVE select PINCTRL_DOVE
select PLAT_ORION_LEGACY select PLAT_ORION_LEGACY
select USB_ARCH_HAS_EHCI select USB_ARCH_HAS_EHCI
select MVEBU_MBUS
help help
Support for the Marvell Dove SoC 88AP510 Support for the Marvell Dove SoC 88AP510
...@@ -511,6 +512,7 @@ config ARCH_KIRKWOOD ...@@ -511,6 +512,7 @@ config ARCH_KIRKWOOD
select PINCTRL select PINCTRL
select PINCTRL_KIRKWOOD select PINCTRL_KIRKWOOD
select PLAT_ORION_LEGACY select PLAT_ORION_LEGACY
select MVEBU_MBUS
help help
Support for the following Marvell Kirkwood series SoCs: Support for the following Marvell Kirkwood series SoCs:
88F6180, 88F6192 and 88F6281. 88F6180, 88F6192 and 88F6281.
...@@ -522,6 +524,7 @@ config ARCH_MV78XX0 ...@@ -522,6 +524,7 @@ config ARCH_MV78XX0
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select PCI select PCI
select PLAT_ORION_LEGACY select PLAT_ORION_LEGACY
select MVEBU_MBUS
help help
Support for the following Marvell MV78xx0 series SoCs: Support for the following Marvell MV78xx0 series SoCs:
MV781x0, MV782x0. MV781x0, MV782x0.
...@@ -534,6 +537,7 @@ config ARCH_ORION5X ...@@ -534,6 +537,7 @@ config ARCH_ORION5X
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select PCI select PCI
select PLAT_ORION_LEGACY select PLAT_ORION_LEGACY
select MVEBU_MBUS
help help
Support for the following Marvell Orion 5x series SoCs: Support for the following Marvell Orion 5x series SoCs:
Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182), Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
......
...@@ -245,11 +245,11 @@ choice ...@@ -245,11 +245,11 @@ choice
on i.MX53. on i.MX53.
config DEBUG_IMX6Q_UART config DEBUG_IMX6Q_UART
bool "i.MX6Q Debug UART" bool "i.MX6Q/DL Debug UART"
depends on SOC_IMX6Q depends on SOC_IMX6Q
help help
Say Y here if you want kernel low-level debugging support Say Y here if you want kernel low-level debugging support
on i.MX6Q. on i.MX6Q/DL.
config DEBUG_MMP_UART2 config DEBUG_MMP_UART2
bool "Kernel low-level debugging message via MMP UART2" bool "Kernel low-level debugging message via MMP UART2"
......
...@@ -73,11 +73,6 @@ timer@d0020300 { ...@@ -73,11 +73,6 @@ timer@d0020300 {
clocks = <&coreclk 2>; clocks = <&coreclk 2>;
}; };
addr-decoding@d0020000 {
compatible = "marvell,armada-addr-decoding-controller";
reg = <0xd0020000 0x258>;
};
sata@d00a0000 { sata@d00a0000 {
compatible = "marvell,orion-sata"; compatible = "marvell,orion-sata";
reg = <0xd00a0000 0x2400>; reg = <0xd00a0000 0x2400>;
......
...@@ -136,5 +136,12 @@ ttc1: ttc1@f8002000 { ...@@ -136,5 +136,12 @@ ttc1: ttc1@f8002000 {
clock-names = "cpu_1x"; clock-names = "cpu_1x";
clock-ranges; 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>;
} ;
}; };
}; };
...@@ -109,6 +109,7 @@ CONFIG_I2C_IMX=y ...@@ -109,6 +109,7 @@ CONFIG_I2C_IMX=y
CONFIG_SPI=y CONFIG_SPI=y
CONFIG_SPI_IMX=y CONFIG_SPI_IMX=y
CONFIG_SPI_SPIDEV=y CONFIG_SPI_SPIDEV=y
CONFIG_GPIO_SYSFS=y
CONFIG_W1=y CONFIG_W1=y
CONFIG_W1_MASTER_MXC=y CONFIG_W1_MASTER_MXC=y
CONFIG_W1_SLAVE_THERM=y CONFIG_W1_SLAVE_THERM=y
......
...@@ -9,6 +9,7 @@ CONFIG_CGROUPS=y ...@@ -9,6 +9,7 @@ CONFIG_CGROUPS=y
CONFIG_RELAY=y CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y CONFIG_EXPERT=y
CONFIG_PERF_EVENTS=y
# CONFIG_SLUB_DEBUG is not set # CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set # CONFIG_COMPAT_BRK is not set
CONFIG_MODULES=y CONFIG_MODULES=y
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
*/ */
#define ARMADA_370_XP_REGS_PHYS_BASE 0xd0000000 #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 .macro addruart, rp, rv, tmp
ldr \rp, =ARMADA_370_XP_REGS_PHYS_BASE ldr \rp, =ARMADA_370_XP_REGS_PHYS_BASE
......
obj-y += common.o addr-map.o irq.o obj-y += common.o irq.o
obj-$(CONFIG_DOVE_LEGACY) += mpp.o obj-$(CONFIG_DOVE_LEGACY) += mpp.o
obj-$(CONFIG_PCI) += pcie.o obj-$(CONFIG_PCI) += pcie.o
obj-$(CONFIG_MACH_DOVE_DB) += dove-db-setup.o obj-$(CONFIG_MACH_DOVE_DB) += dove-db-setup.o
......
/*
* 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;
}
...@@ -64,7 +64,7 @@ static void __init dove_dt_init(void) ...@@ -64,7 +64,7 @@ static void __init dove_dt_init(void)
#ifdef CONFIG_CACHE_TAUROS2 #ifdef CONFIG_CACHE_TAUROS2
tauros2_init(0); tauros2_init(0);
#endif #endif
dove_setup_cpu_mbus(); dove_setup_cpu_wins();
/* Setup root of clk tree */ /* Setup root of clk tree */
dove_of_clk_init(); dove_of_clk_init();
......
...@@ -224,6 +224,9 @@ void __init dove_i2c_init(void) ...@@ -224,6 +224,9 @@ void __init dove_i2c_init(void)
void __init dove_init_early(void) void __init dove_init_early(void)
{ {
orion_time_set_base(TIMER_VIRT_BASE); 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) static int __init dove_find_tclk(void)
...@@ -326,6 +329,40 @@ void __init dove_sdio1_init(void) ...@@ -326,6 +329,40 @@ void __init dove_sdio1_init(void)
platform_device_register(&dove_sdio1); 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) void __init dove_init(void)
{ {
pr_info("Dove 88AP510 SoC, TCLK = %d MHz.\n", pr_info("Dove 88AP510 SoC, TCLK = %d MHz.\n",
...@@ -334,7 +371,7 @@ void __init dove_init(void) ...@@ -334,7 +371,7 @@ void __init dove_init(void)
#ifdef CONFIG_CACHE_TAUROS2 #ifdef CONFIG_CACHE_TAUROS2
tauros2_init(0); tauros2_init(0);
#endif #endif
dove_setup_cpu_mbus(); dove_setup_cpu_wins();
/* Setup root of clk tree */ /* Setup root of clk tree */
dove_clk_init(); dove_clk_init();
......
...@@ -23,7 +23,7 @@ void dove_map_io(void); ...@@ -23,7 +23,7 @@ void dove_map_io(void);
void dove_init(void); void dove_init(void);
void dove_init_early(void); void dove_init_early(void);
void dove_init_irq(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_ge00_init(struct mv643xx_eth_platform_data *eth_data);
void dove_sata_init(struct mv_sata_platform_data *sata_data); void dove_sata_init(struct mv_sata_platform_data *sata_data);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
......
...@@ -77,6 +77,8 @@ ...@@ -77,6 +77,8 @@
/* North-South Bridge */ /* North-South Bridge */
#define BRIDGE_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0x20000) #define BRIDGE_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0x20000)
#define BRIDGE_PHYS_BASE (DOVE_SB_REGS_PHYS_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 */ /* Cryptographic Engine */
#define DOVE_CRYPT_PHYS_BASE (DOVE_SB_REGS_PHYS_BASE + 0x30000) #define DOVE_CRYPT_PHYS_BASE (DOVE_SB_REGS_PHYS_BASE + 0x30000)
...@@ -168,6 +170,9 @@ ...@@ -168,6 +170,9 @@
#define DOVE_SSP_CLOCK_ENABLE (1 << 1) #define DOVE_SSP_CLOCK_ENABLE (1 << 1)
#define DOVE_SSP_BPB_CLOCK_SRC_SSP (1 << 11) #define DOVE_SSP_BPB_CLOCK_SRC_SSP (1 << 11)
/* Memory Controller */ /* 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) #define DOVE_MC_VIRT_BASE (DOVE_NB_REGS_VIRT_BASE + 0x00000)
/* LCD Controller */ /* LCD Controller */
......
...@@ -65,6 +65,9 @@ config IRAM_ALLOC ...@@ -65,6 +65,9 @@ config IRAM_ALLOC
bool bool
select GENERIC_ALLOCATOR select GENERIC_ALLOCATOR
config HAVE_IMX_ANATOP
bool
config HAVE_IMX_GPC config HAVE_IMX_GPC
bool bool
...@@ -73,6 +76,7 @@ config HAVE_IMX_MMDC ...@@ -73,6 +76,7 @@ config HAVE_IMX_MMDC
config HAVE_IMX_SRC config HAVE_IMX_SRC
def_bool y if SMP def_bool y if SMP
select ARCH_HAS_RESET_CONTROLLER
config IMX_HAVE_IOMUX_V1 config IMX_HAVE_IOMUX_V1
bool bool
...@@ -115,6 +119,8 @@ config SOC_IMX25 ...@@ -115,6 +119,8 @@ config SOC_IMX25
config SOC_IMX27 config SOC_IMX27
bool bool
select ARCH_HAS_CPUFREQ
select ARCH_HAS_OPP
select COMMON_CLK select COMMON_CLK
select CPU_ARM926T select CPU_ARM926T
select IMX_HAVE_IOMUX_V1 select IMX_HAVE_IOMUX_V1
...@@ -142,6 +148,7 @@ config SOC_IMX35 ...@@ -142,6 +148,7 @@ config SOC_IMX35
config SOC_IMX5 config SOC_IMX5
bool bool
select ARCH_HAS_CPUFREQ select ARCH_HAS_CPUFREQ
select ARCH_HAS_OPP
select ARCH_MXC_IOMUX_V3 select ARCH_MXC_IOMUX_V3
select COMMON_CLK select COMMON_CLK
select CPU_V7 select CPU_V7
...@@ -783,7 +790,7 @@ config SOC_IMX53 ...@@ -783,7 +790,7 @@ config SOC_IMX53
This enables support for Freescale i.MX53 processor. This enables support for Freescale i.MX53 processor.
config SOC_IMX6Q config SOC_IMX6Q
bool "i.MX6 Quad support" bool "i.MX6 Quad/DualLite support"
select ARCH_HAS_CPUFREQ select ARCH_HAS_CPUFREQ
select ARCH_HAS_OPP select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM select ARM_CPU_SUSPEND if PM
...@@ -796,6 +803,7 @@ config SOC_IMX6Q ...@@ -796,6 +803,7 @@ config SOC_IMX6Q
select HAVE_ARM_SCU if SMP select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if LOCAL_TIMERS select HAVE_ARM_TWD if LOCAL_TIMERS
select HAVE_CAN_FLEXCAN if CAN select HAVE_CAN_FLEXCAN if CAN
select HAVE_IMX_ANATOP
select HAVE_IMX_GPC select HAVE_IMX_GPC
select HAVE_IMX_MMDC select HAVE_IMX_MMDC
select HAVE_IMX_SRC select HAVE_IMX_SRC
......
...@@ -91,6 +91,7 @@ obj-$(CONFIG_MACH_EUKREA_CPUIMX35SD) += mach-cpuimx35.o ...@@ -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_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o
obj-$(CONFIG_MACH_VPR200) += mach-vpr200.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_GPC) += gpc.o
obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
obj-$(CONFIG_HAVE_IMX_SRC) += src.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o
......
/*
* 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;
}
}
...@@ -45,16 +45,40 @@ static const char *mx53_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", " ...@@ -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 *mx53_ldb_di1_sel[] = { "pll3_sw", "pll4_sw", };
static const char *mx51_tve_ext_sel[] = { "osc", "ckih1", }; static const char *mx51_tve_ext_sel[] = { "osc", "ckih1", };
static const char *mx53_tve_ext_sel[] = { "pll4_sw", "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 *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 *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_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 { enum imx5_clks {
dummy, ckil, osc, ckih1, ckih2, ahb, ipg, axi_a, axi_b, uart_pred, 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, 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, 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, tve_s, uart1_ipg_gate, uart1_per_gate, uart2_ipg_gate,
uart2_per_gate, uart3_ipg_gate, uart3_per_gate, i2c1_gate, i2c2_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, gpt_ipg_gate, pwm1_ipg_gate, pwm1_hf_gate, pwm2_ipg_gate, pwm2_hf_gate,
...@@ -83,7 +107,10 @@ enum imx5_clks { ...@@ -83,7 +107,10 @@ enum imx5_clks {
ssi2_root_gate, ssi3_root_gate, ssi_ext1_gate, ssi_ext2_gate, ssi2_root_gate, ssi3_root_gate, ssi_ext1_gate, ssi_ext2_gate,
epit1_ipg_gate, epit1_hf_gate, epit2_ipg_gate, epit2_hf_gate, epit1_ipg_gate, epit1_hf_gate, epit2_ipg_gate, epit2_hf_gate,
can_sel, can1_serial_gate, can1_ipg_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 clk_max
}; };
...@@ -160,8 +187,6 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil, ...@@ -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)); 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[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[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[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_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); 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, ...@@ -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[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_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[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_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_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); 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, ...@@ -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_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[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[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++) for (i = 0; i < ARRAY_SIZE(clk); i++)
if (IS_ERR(clk[i])) if (IS_ERR(clk[i]))
...@@ -286,7 +318,6 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil, ...@@ -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.0");
clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.1"); clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.1");
clk_register_clkdev(clk[dummy], NULL, "imx-keypad"); 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[ipu_di1_gate], "di1", "imx-tve.0");
clk_register_clkdev(clk[gpc_dvfs], "gpc_dvfs", NULL); clk_register_clkdev(clk[gpc_dvfs], "gpc_dvfs", NULL);
clk_register_clkdev(clk[epit1_ipg_gate], "ipg", "imx-epit.0"); 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, ...@@ -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)); 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, 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)); 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, 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)); 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_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[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); 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, ...@@ -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[pll3_sw] = imx_clk_pllv2("pll3_sw", "osc", MX53_DPLL3_BASE);
clk[pll4_sw] = imx_clk_pllv2("pll4_sw", "osc", MX53_DPLL4_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_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[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_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_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[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, 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)); 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, 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)); 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, 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)); 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_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[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); 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, ...@@ -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[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[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++) for (i = 0; i < ARRAY_SIZE(clk); i++)
if (IS_ERR(clk[i])) if (IS_ERR(clk[i]))
pr_err("i.MX53 clk %d: register failed with %ld\n", pr_err("i.MX53 clk %d: register failed with %ld\n",
......
/* /*
* Copyright 2011 Freescale Semiconductor, Inc. * Copyright 2011-2013 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd. * Copyright 2011 Linaro Ltd.
* *
* The code contained herein is licensed under the GNU General Public * The code contained herein is licensed under the GNU General Public
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -22,6 +23,12 @@ ...@@ -22,6 +23,12 @@
#include "clk.h" #include "clk.h"
#include "common.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 CCGR0 0x68
#define CCGR1 0x6c #define CCGR1 0x6c
...@@ -67,6 +74,67 @@ void imx6q_set_chicken_bit(void) ...@@ -67,6 +74,67 @@ void imx6q_set_chicken_bit(void)
writel_relaxed(val, ccm_base + CGPR); 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) int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
{ {
u32 val = readl_relaxed(ccm_base + CLPCR); u32 val = readl_relaxed(ccm_base + CLPCR);
...@@ -74,6 +142,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) ...@@ -74,6 +142,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
val &= ~BM_CLPCR_LPM; val &= ~BM_CLPCR_LPM;
switch (mode) { switch (mode) {
case WAIT_CLOCKED: case WAIT_CLOCKED:
imx6q_enable_wb(false);
imx6q_enable_rbc(false);
break; break;
case WAIT_UNCLOCKED: case WAIT_UNCLOCKED:
val |= 0x1 << BP_CLPCR_LPM; val |= 0x1 << BP_CLPCR_LPM;
...@@ -92,6 +162,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) ...@@ -92,6 +162,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
val |= 0x3 << BP_CLPCR_STBY_COUNT; val |= 0x3 << BP_CLPCR_STBY_COUNT;
val |= BM_CLPCR_VSTBY; val |= BM_CLPCR_VSTBY;
val |= BM_CLPCR_SBYOS; val |= BM_CLPCR_SBYOS;
imx6q_enable_wb(true);
imx6q_enable_rbc(true);
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -109,29 +181,29 @@ static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", }; ...@@ -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 *periph_sels[] = { "periph_pre", "periph_clk2", };
static const char *periph2_sels[] = { "periph2_pre", "periph2_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 *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 *gpu_axi_sels[] = { "axi", "ahb", };
static const char *gpu2d_core_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", }; 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_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 *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 *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 *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_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 *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_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 *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 *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", };
static const char *pcie_axi_sels[] = { "axi", "ahb", }; 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 *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 *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 *emi_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", };
static const char *vdo_axi_sels[] = { "axi", "ahb", }; static const char *vdo_axi_sels[] = { "axi", "ahb", };
static const char *vpu_axi_sels[] = { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m", }; 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", "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 { enum mx6q_clks {
dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m,
...@@ -165,7 +237,7 @@ enum mx6q_clks { ...@@ -165,7 +237,7 @@ enum mx6q_clks {
pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg, 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, 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, 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]; static struct clk *clk[clk_max];
...@@ -182,6 +254,21 @@ static struct clk_div_table clk_enet_ref_table[] = { ...@@ -182,6 +254,21 @@ static struct clk_div_table clk_enet_ref_table[] = {
{ .val = 3, .div = 4, }, { .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) int __init mx6q_clocks_init(void)
{ {
struct device_node *np; struct device_node *np;
...@@ -208,6 +295,14 @@ int __init mx6q_clocks_init(void) ...@@ -208,6 +295,14 @@ int __init mx6q_clocks_init(void)
base = of_iomap(np, 0); base = of_iomap(np, 0);
WARN_ON(!base); 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 */ /* type name parent_name base div_mask */
clk[pll1_sys] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); 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); 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) ...@@ -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[pll3_60m] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
clk[twd] = imx_clk_fixed_factor("twd", "arm", 1, 2); 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"); np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm");
base = of_iomap(np, 0); base = of_iomap(np, 0);
WARN_ON(!base); WARN_ON(!base);
...@@ -283,8 +382,8 @@ int __init mx6q_clocks_init(void) ...@@ -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[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[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[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_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("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); 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_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[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)); 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) ...@@ -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[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[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_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_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_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[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); 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) ...@@ -448,6 +547,11 @@ int __init mx6q_clocks_init(void)
clk_register_clkdev(clk[cko1], "cko1", NULL); clk_register_clkdev(clk[cko1], "cko1", NULL);
clk_register_clkdev(clk[arm], NULL, "cpu0"); 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, * The gpmi needs 100MHz frequency in the EDO/Sync mode,
* We can not get the 100MHz from the pll2_pfd0_352m. * We can not get the 100MHz from the pll2_pfd0_352m.
......
...@@ -59,6 +59,14 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, ...@@ -59,6 +59,14 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent,
reg, shift, width, 0, &imx_ccm_lock); 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, static inline struct clk *imx_clk_gate(const char *name, const char *parent,
void __iomem *reg, u8 shift) void __iomem *reg, u8 shift)
{ {
...@@ -73,6 +81,15 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, ...@@ -73,6 +81,15 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
width, 0, &imx_ccm_lock); 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, static inline struct clk *imx_clk_fixed_factor(const char *name,
const char *parent, unsigned int mult, unsigned int div) const char *parent, unsigned int mult, unsigned int div)
{ {
......
/* /*
* 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); ...@@ -74,6 +74,7 @@ extern void mxc_set_cpu_type(unsigned int type);
extern void mxc_restart(char, const char *); extern void mxc_restart(char, const char *);
extern void mxc_arch_reset_init(void __iomem *); extern void mxc_arch_reset_init(void __iomem *);
extern int mx53_revision(void); extern int mx53_revision(void);
extern int imx6q_revision(void);
extern int mx53_display_revision(void); extern int mx53_display_revision(void);
extern void imx_set_aips(void __iomem *); extern void imx_set_aips(void __iomem *);
extern int mxc_device_init(void); extern int mxc_device_init(void);
...@@ -128,6 +129,13 @@ extern void imx_src_prepare_restart(void); ...@@ -128,6 +129,13 @@ extern void imx_src_prepare_restart(void);
extern void imx_gpc_init(void); extern void imx_gpc_init(void);
extern void imx_gpc_pre_suspend(void); extern void imx_gpc_pre_suspend(void);
extern void imx_gpc_post_resume(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 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
extern void imx6q_set_chicken_bit(void); extern void imx6q_set_chicken_bit(void);
......
/* /*
* Copyright 2011 Freescale Semiconductor, Inc. * Copyright 2011-2013 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd. * Copyright 2011 Linaro Ltd.
* *
* The code contained herein is licensed under the GNU General Public * 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) ...@@ -69,6 +69,27 @@ static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
return 0; 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) static void imx_gpc_irq_unmask(struct irq_data *d)
{ {
void __iomem *reg; void __iomem *reg;
......
/* /*
* Copyright 2011 Freescale Semiconductor, Inc. * Copyright 2011-2013 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd. * Copyright 2011 Linaro Ltd.
* *
* The code contained herein is licensed under the GNU General Public * The code contained herein is licensed under the GNU General Public
...@@ -38,38 +38,32 @@ ...@@ -38,38 +38,32 @@
#include "cpuidle.h" #include "cpuidle.h"
#include "hardware.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; return chip_revision;
void __iomem *base; }
static u32 rev;
static void __init imx6q_init_revision(void)
if (!rev) { {
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); u32 rev = imx_anatop_get_digprog();
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);
}
switch (rev & 0xff) { switch (rev & 0xff) {
case 0: case 0:
return IMX_CHIP_REVISION_1_0; chip_revision = IMX_CHIP_REVISION_1_0;
break;
case 1: case 1:
return IMX_CHIP_REVISION_1_1; chip_revision = IMX_CHIP_REVISION_1_1;
break;
case 2: case 2:
return IMX_CHIP_REVISION_1_2; chip_revision = IMX_CHIP_REVISION_1_2;
break;
default: 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) static void imx6q_restart(char mode, const char *cmd)
...@@ -164,29 +158,7 @@ static void __init imx6q_1588_init(void) ...@@ -164,29 +158,7 @@ static void __init imx6q_1588_init(void)
} }
static void __init imx6q_usb_init(void) static void __init imx6q_usb_init(void)
{ {
struct regmap *anatop; imx_anatop_usb_chrg_detect_disable();
#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");
}
} }
static void __init imx6q_init_machine(void) static void __init imx6q_init_machine(void)
...@@ -196,6 +168,7 @@ 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); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
imx_anatop_init();
imx6q_pm_init(); imx6q_pm_init();
imx6q_usb_init(); imx6q_usb_init();
imx6q_1588_init(); imx6q_1588_init();
...@@ -282,6 +255,7 @@ static void __init imx6q_map_io(void) ...@@ -282,6 +255,7 @@ static void __init imx6q_map_io(void)
static void __init imx6q_init_irq(void) static void __init imx6q_init_irq(void)
{ {
imx6q_init_revision();
l2x0_of_init(0, ~0UL); l2x0_of_init(0, ~0UL);
imx_src_init(); imx_src_init();
imx_gpc_init(); imx_gpc_init();
...@@ -292,15 +266,17 @@ static void __init imx6q_timer_init(void) ...@@ -292,15 +266,17 @@ static void __init imx6q_timer_init(void)
{ {
mx6q_clocks_init(); mx6q_clocks_init();
clocksource_of_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 = { static const char *imx6q_dt_compat[] __initdata = {
"fsl,imx6dl",
"fsl,imx6q", "fsl,imx6q",
NULL, 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), .smp = smp_ops(imx_smp_ops),
.map_io = imx6q_map_io, .map_io = imx6q_map_io,
.init_irq = imx6q_init_irq, .init_irq = imx6q_init_irq,
......
...@@ -51,6 +51,8 @@ void __init mx1_init_irq(void) ...@@ -51,6 +51,8 @@ void __init mx1_init_irq(void)
void __init imx1_soc_init(void) void __init imx1_soc_init(void)
{ {
mxc_device_init();
mxc_register_gpio("imx1-gpio", 0, MX1_GPIO1_BASE_ADDR, SZ_256, mxc_register_gpio("imx1-gpio", 0, MX1_GPIO1_BASE_ADDR, SZ_256,
MX1_GPIO_INT_PORTA, 0); MX1_GPIO_INT_PORTA, 0);
mxc_register_gpio("imx1-gpio", 1, MX1_GPIO2_BASE_ADDR, SZ_256, mxc_register_gpio("imx1-gpio", 1, MX1_GPIO2_BASE_ADDR, SZ_256,
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#define MXC_CPU_MX35 35 #define MXC_CPU_MX35 35
#define MXC_CPU_MX51 51 #define MXC_CPU_MX51 51
#define MXC_CPU_MX53 53 #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_0 0x10
#define IMX_CHIP_REVISION_1_1 0x11 #define IMX_CHIP_REVISION_1_1 0x11
...@@ -150,6 +152,15 @@ extern unsigned int __mxc_cpu_type; ...@@ -150,6 +152,15 @@ extern unsigned int __mxc_cpu_type;
#endif #endif
#ifndef __ASSEMBLY__ #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 { struct cpu_op {
u32 cpu_rate; u32 cpu_rate;
......
...@@ -68,8 +68,8 @@ static void __init imx_smp_init_cpus(void) ...@@ -68,8 +68,8 @@ static void __init imx_smp_init_cpus(void)
ncores = scu_get_core_count(scu_base); ncores = scu_get_core_count(scu_base);
for (i = 0; i < ncores; i++) for (i = ncores; i < NR_CPUS; i++)
set_cpu_possible(i, true); set_cpu_possible(i, false);
} }
void imx_smp_prepare(void) void imx_smp_prepare(void)
......
/* /*
* Copyright 2011 Freescale Semiconductor, Inc. * Copyright 2011-2013 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd. * Copyright 2011 Linaro Ltd.
* *
* The code contained herein is licensed under the GNU General Public * The code contained herein is licensed under the GNU General Public
...@@ -34,10 +34,12 @@ static int imx6q_pm_enter(suspend_state_t state) ...@@ -34,10 +34,12 @@ static int imx6q_pm_enter(suspend_state_t state)
case PM_SUSPEND_MEM: case PM_SUSPEND_MEM:
imx6q_set_lpm(STOP_POWER_OFF); imx6q_set_lpm(STOP_POWER_OFF);
imx_gpc_pre_suspend(); imx_gpc_pre_suspend();
imx_anatop_pre_suspend();
imx_set_cpu_jump(0, v7_cpu_resume); imx_set_cpu_jump(0, v7_cpu_resume);
/* Zzz ... */ /* Zzz ... */
cpu_suspend(0, imx6q_suspend_finish); cpu_suspend(0, imx6q_suspend_finish);
imx_smp_prepare(); imx_smp_prepare();
imx_anatop_post_resume();
imx_gpc_post_resume(); imx_gpc_post_resume();
imx6q_set_lpm(WAIT_CLOCKED); imx6q_set_lpm(WAIT_CLOCKED);
break; break;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include "common.h" #include "common.h"
...@@ -21,10 +22,65 @@ ...@@ -21,10 +22,65 @@
#define SRC_SCR 0x000 #define SRC_SCR 0x000
#define SRC_GPR1 0x020 #define SRC_GPR1 0x020
#define BP_SRC_SCR_WARM_RESET_ENABLE 0 #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_RST 14
#define BP_SRC_SCR_CORE1_ENABLE 22 #define BP_SRC_SCR_CORE1_ENABLE 22
static void __iomem *src_base; 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) void imx_enable_cpu(int cpu, bool enable)
{ {
...@@ -32,9 +88,11 @@ 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); cpu = cpu_logical_map(cpu);
mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
spin_lock(&scr_lock);
val = readl_relaxed(src_base + SRC_SCR); val = readl_relaxed(src_base + SRC_SCR);
val = enable ? val | mask : val & ~mask; val = enable ? val | mask : val & ~mask;
writel_relaxed(val, src_base + SRC_SCR); writel_relaxed(val, src_base + SRC_SCR);
spin_unlock(&scr_lock);
} }
void imx_set_cpu_jump(int cpu, void *jump_addr) void imx_set_cpu_jump(int cpu, void *jump_addr)
...@@ -61,9 +119,11 @@ void imx_src_prepare_restart(void) ...@@ -61,9 +119,11 @@ void imx_src_prepare_restart(void)
u32 val; u32 val;
/* clear enable bits of secondary cores */ /* clear enable bits of secondary cores */
spin_lock(&scr_lock);
val = readl_relaxed(src_base + SRC_SCR); val = readl_relaxed(src_base + SRC_SCR);
val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE); val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE);
writel_relaxed(val, src_base + SRC_SCR); writel_relaxed(val, src_base + SRC_SCR);
spin_unlock(&scr_lock);
/* clear persistent entry register of primary core */ /* clear persistent entry register of primary core */
writel_relaxed(0, src_base + SRC_GPR1); writel_relaxed(0, src_base + SRC_GPR1);
...@@ -80,11 +140,17 @@ void __init imx_src_init(void) ...@@ -80,11 +140,17 @@ void __init imx_src_init(void)
src_base = of_iomap(np, 0); src_base = of_iomap(np, 0);
WARN_ON(!src_base); 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 * force warm reset sources to generate cold reset
* for a more reliable restart * for a more reliable restart
*/ */
spin_lock(&scr_lock);
val = readl_relaxed(src_base + SRC_SCR); val = readl_relaxed(src_base + SRC_SCR);
val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
writel_relaxed(val, src_base + SRC_SCR); writel_relaxed(val, src_base + SRC_SCR);
spin_unlock(&scr_lock);
} }
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_D2NET_V2) += d2net_v2-setup.o lacie_v2-common.o
obj-$(CONFIG_MACH_DB88F6281_BP) += db88f6281-bp-setup.o obj-$(CONFIG_MACH_DB88F6281_BP) += db88f6281-bp-setup.o
......
/*
* 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);
}
...@@ -93,7 +93,7 @@ static void __init kirkwood_dt_init(void) ...@@ -93,7 +93,7 @@ static void __init kirkwood_dt_init(void)
*/ */
writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG); writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG);
kirkwood_setup_cpu_mbus(); kirkwood_setup_wins();
kirkwood_l2_init(); kirkwood_l2_init();
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include <linux/platform_data/usb-ehci-orion.h> #include <linux/platform_data/usb-ehci-orion.h>
#include <plat/common.h> #include <plat/common.h>
#include <plat/time.h> #include <plat/time.h>
#include <plat/addr-map.h>
#include <linux/platform_data/dma-mv_xor.h> #include <linux/platform_data/dma-mv_xor.h>
#include "common.h" #include "common.h"
...@@ -535,6 +534,9 @@ void __init kirkwood_init_early(void) ...@@ -535,6 +534,9 @@ void __init kirkwood_init_early(void)
* the allocations won't fail. * the allocations won't fail.
*/ */
init_dma_coherent_pool_size(SZ_1M); 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; int kirkwood_tclk;
...@@ -650,6 +652,38 @@ char * __init kirkwood_id(void) ...@@ -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) void __init kirkwood_l2_init(void)
{ {
#ifdef CONFIG_CACHE_FEROCEON_L2 #ifdef CONFIG_CACHE_FEROCEON_L2
...@@ -675,7 +709,7 @@ void __init kirkwood_init(void) ...@@ -675,7 +709,7 @@ void __init kirkwood_init(void)
*/ */
writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG); writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG);
kirkwood_setup_cpu_mbus(); kirkwood_setup_wins();
kirkwood_l2_init(); kirkwood_l2_init();
......
...@@ -30,7 +30,7 @@ void kirkwood_init(void); ...@@ -30,7 +30,7 @@ void kirkwood_init(void);
void kirkwood_init_early(void); void kirkwood_init_early(void);
void kirkwood_init_irq(void); void kirkwood_init_irq(void);
void kirkwood_setup_cpu_mbus(void); void kirkwood_setup_wins(void);
void kirkwood_enable_pcie(void); void kirkwood_enable_pcie(void);
void kirkwood_pcie_id(u32 *dev, u32 *rev); void kirkwood_pcie_id(u32 *dev, u32 *rev);
......
...@@ -60,8 +60,9 @@ ...@@ -60,8 +60,9 @@
* Register Map * Register Map
*/ */
#define DDR_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE + 0x00000) #define DDR_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE + 0x00000)
#define DDR_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x00000) #define DDR_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x00000)
#define DDR_WINDOW_CPU_BASE (DDR_VIRT_BASE + 0x1500) #define DDR_WINDOW_CPU_BASE (DDR_PHYS_BASE + 0x1500)
#define DDR_WINDOW_CPU_SZ (0x20)
#define DDR_OPERATION_BASE (DDR_PHYS_BASE + 0x1418) #define DDR_OPERATION_BASE (DDR_PHYS_BASE + 0x1418)
#define DEV_BUS_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x10000) #define DEV_BUS_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x10000)
...@@ -80,6 +81,8 @@ ...@@ -80,6 +81,8 @@
#define BRIDGE_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE + 0x20000) #define BRIDGE_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE + 0x20000)
#define BRIDGE_PHYS_BASE (KIRKWOOD_REGS_PHYS_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) #define CRYPTO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE + 0x30000)
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <asm/mach/pci.h> #include <asm/mach/pci.h>
#include <plat/pcie.h> #include <plat/pcie.h>
#include <mach/bridge-regs.h> #include <mach/bridge-regs.h>
#include <plat/addr-map.h>
#include "common.h" #include "common.h"
static void kirkwood_enable_pcie_clk(const char *port) static void kirkwood_enable_pcie_clk(const char *port)
......
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_DB78X00_BP) += db78x00-bp-setup.o
obj-$(CONFIG_MACH_RD78X00_MASA) += rd78x00-masa-setup.o obj-$(CONFIG_MACH_RD78X00_MASA) += rd78x00-masa-setup.o
obj-$(CONFIG_MACH_TERASTATION_WXL) += buffalo-wxl-setup.o obj-$(CONFIG_MACH_TERASTATION_WXL) += buffalo-wxl-setup.o
/*
* 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);
}
...@@ -334,6 +334,14 @@ void __init mv78xx0_uart3_init(void) ...@@ -334,6 +334,14 @@ void __init mv78xx0_uart3_init(void)
void __init mv78xx0_init_early(void) void __init mv78xx0_init_early(void)
{ {
orion_time_set_base(TIMER_VIRT_BASE); 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) void __init_refok mv78xx0_timer_init(void)
...@@ -397,8 +405,6 @@ void __init mv78xx0_init(void) ...@@ -397,8 +405,6 @@ void __init mv78xx0_init(void)
printk("HCLK = %dMHz, ", (hclk + 499999) / 1000000); printk("HCLK = %dMHz, ", (hclk + 499999) / 1000000);
printk("TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000); printk("TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000);
mv78xx0_setup_cpu_mbus();
#ifdef CONFIG_CACHE_FEROCEON_L2 #ifdef CONFIG_CACHE_FEROCEON_L2
feroceon_l2_init(is_l2_writethrough()); feroceon_l2_init(is_l2_writethrough());
#endif #endif
......
...@@ -60,13 +60,18 @@ ...@@ -60,13 +60,18 @@
*/ */
#define BRIDGE_VIRT_BASE (MV78XX0_CORE_REGS_VIRT_BASE) #define BRIDGE_VIRT_BASE (MV78XX0_CORE_REGS_VIRT_BASE)
#define BRIDGE_PHYS_BASE (MV78XX0_CORE_REGS_PHYS_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 * Register Map
*/ */
#define DDR_VIRT_BASE (MV78XX0_REGS_VIRT_BASE + 0x00000) #define DDR_VIRT_BASE (MV78XX0_REGS_VIRT_BASE + 0x00000)
#define DDR_WINDOW_CPU0_BASE (DDR_VIRT_BASE + 0x1500) #define DDR_PHYS_BASE (MV78XX0_REGS_PHYS_BASE + 0x00000)
#define DDR_WINDOW_CPU1_BASE (DDR_VIRT_BASE + 0x1570) #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_PHYS_BASE (MV78XX0_REGS_PHYS_BASE + 0x10000)
#define DEV_BUS_VIRT_BASE (MV78XX0_REGS_VIRT_BASE + 0x10000) #define DEV_BUS_VIRT_BASE (MV78XX0_REGS_VIRT_BASE + 0x10000)
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/mbus.h>
#include <video/vga.h> #include <video/vga.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/pci.h> #include <asm/mach/pci.h>
#include <plat/pcie.h> #include <plat/pcie.h>
#include <plat/addr-map.h>
#include <mach/mv78xx0.h> #include <mach/mv78xx0.h>
#include "common.h" #include "common.h"
...@@ -54,7 +54,6 @@ static void __init mv78xx0_pcie_preinit(void) ...@@ -54,7 +54,6 @@ static void __init mv78xx0_pcie_preinit(void)
int i; int i;
u32 size_each; u32 size_each;
u32 start; u32 start;
int win = 0;
pcie_io_space.name = "PCIe I/O Space"; pcie_io_space.name = "PCIe I/O Space";
pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0); pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0);
...@@ -72,6 +71,7 @@ static void __init mv78xx0_pcie_preinit(void) ...@@ -72,6 +71,7 @@ static void __init mv78xx0_pcie_preinit(void)
start = MV78XX0_PCIE_MEM_PHYS_BASE; start = MV78XX0_PCIE_MEM_PHYS_BASE;
for (i = 0; i < num_pcie_ports; i++) { for (i = 0; i < num_pcie_ports; i++) {
struct pcie_port *pp = pcie_port + 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), snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
"PCIe %d.%d MEM", pp->maj, pp->min); "PCIe %d.%d MEM", pp->maj, pp->min);
...@@ -85,12 +85,17 @@ static void __init mv78xx0_pcie_preinit(void) ...@@ -85,12 +85,17 @@ static void __init mv78xx0_pcie_preinit(void)
if (request_resource(&iomem_resource, &pp->res)) if (request_resource(&iomem_resource, &pp->res))
panic("can't allocate PCIe MEM sub-space"); panic("can't allocate PCIe MEM sub-space");
mv78xx0_setup_pcie_mem_win(win + i + 8, pp->res.start, snprintf(winname, sizeof(winname), "pcie%d.%d",
resource_size(&pp->res), pp->maj, pp->min);
pp->maj, pp->min);
mvebu_mbus_add_window_remap_flags(winname,
mv78xx0_setup_pcie_io_win(win + i, i * SZ_64K, SZ_64K, pp->res.start,
pp->maj, pp->min); 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);
} }
} }
......
...@@ -13,6 +13,8 @@ config ARCH_MVEBU ...@@ -13,6 +13,8 @@ config ARCH_MVEBU
select MVEBU_CLK_CORE select MVEBU_CLK_CORE
select MVEBU_CLK_CPU select MVEBU_CLK_CPU
select MVEBU_CLK_GATING select MVEBU_CLK_GATING
select MVEBU_MBUS
select ZONE_DMA if ARM_LPAE
if ARCH_MVEBU if ARCH_MVEBU
......
...@@ -5,6 +5,6 @@ AFLAGS_coherency_ll.o := -Wa,-march=armv7-a ...@@ -5,6 +5,6 @@ AFLAGS_coherency_ll.o := -Wa,-march=armv7-a
obj-y += system-controller.o obj-y += system-controller.o
obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.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_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
/*
* 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);
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/time-armada-370-xp.h> #include <linux/time-armada-370-xp.h>
#include <linux/clk/mvebu.h> #include <linux/clk/mvebu.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/mbus.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
...@@ -48,12 +49,29 @@ void __init armada_370_xp_timer_and_clk_init(void) ...@@ -48,12 +49,29 @@ void __init armada_370_xp_timer_and_clk_init(void)
void __init armada_370_xp_init_early(void) void __init armada_370_xp_init_early(void)
{ {
char *mbus_soc_name;
/* /*
* Some Armada 370/XP devices allocate their coherent buffers * Some Armada 370/XP devices allocate their coherent buffers
* from atomic context. Increase size of atomic coherent pool * from atomic context. Increase size of atomic coherent pool
* to make sure such the allocations won't fail. * to make sure such the allocations won't fail.
*/ */
init_dma_coherent_pool_size(SZ_1M); 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) static void __init armada_370_xp_dt_init(void)
......
...@@ -16,9 +16,15 @@ ...@@ -16,9 +16,15 @@
#define __MACH_ARMADA_370_XP_H #define __MACH_ARMADA_370_XP_H
#define ARMADA_370_XP_REGS_PHYS_BASE 0xd0000000 #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 #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 #ifdef CONFIG_SMP
#include <linux/cpumask.h> #include <linux/cpumask.h>
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/mbus.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include "common.h" #include "common.h"
...@@ -109,6 +110,7 @@ void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) ...@@ -109,6 +110,7 @@ void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
set_secondary_cpus_clock(); set_secondary_cpus_clock();
flush_cache_all(); flush_cache_all();
set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); 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 = { struct smp_operations armada_xp_smp_ops __initdata = {
......
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_DB88F5281) += db88f5281-setup.o
obj-$(CONFIG_MACH_RD88F5182) += rd88f5182-setup.o obj-$(CONFIG_MACH_RD88F5182) += rd88f5182-setup.o
obj-$(CONFIG_MACH_KUROBOX_PRO) += kurobox_pro-setup.o obj-$(CONFIG_MACH_KUROBOX_PRO) += kurobox_pro-setup.o
......
/*
* 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);
}
...@@ -42,7 +42,7 @@ static void __init orion5x_dt_init(void) ...@@ -42,7 +42,7 @@ static void __init orion5x_dt_init(void)
/* /*
* Setup Orion address map * Setup Orion address map
*/ */
orion5x_setup_cpu_mbus_bridge(); orion5x_setup_wins();
/* Setup root of clk tree */ /* Setup root of clk tree */
clk_init(); clk_init();
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include <linux/platform_data/usb-ehci-orion.h> #include <linux/platform_data/usb-ehci-orion.h>
#include <plat/time.h> #include <plat/time.h>
#include <plat/common.h> #include <plat/common.h>
#include <plat/addr-map.h>
#include "common.h" #include "common.h"
/***************************************************************************** /*****************************************************************************
...@@ -175,7 +174,8 @@ void __init orion5x_xor_init(void) ...@@ -175,7 +174,8 @@ void __init orion5x_xor_init(void)
****************************************************************************/ ****************************************************************************/
static void __init orion5x_crypto_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, orion_crypto_init(ORION5X_CRYPTO_PHYS_BASE, ORION5X_SRAM_PHYS_BASE,
SZ_8K, IRQ_ORION5X_CESA); SZ_8K, IRQ_ORION5X_CESA);
} }
...@@ -194,6 +194,9 @@ void __init orion5x_wdt_init(void) ...@@ -194,6 +194,9 @@ void __init orion5x_wdt_init(void)
****************************************************************************/ ****************************************************************************/
void __init orion5x_init_early(void) void __init orion5x_init_early(void)
{ {
u32 rev, dev;
const char *mbus_soc_name;
orion_time_set_base(TIMER_VIRT_BASE); orion_time_set_base(TIMER_VIRT_BASE);
/* /*
...@@ -202,6 +205,46 @@ void __init orion5x_init_early(void) ...@@ -202,6 +205,46 @@ void __init orion5x_init_early(void)
* the allocations won't fail. * the allocations won't fail.
*/ */
init_dma_coherent_pool_size(SZ_1M); 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; int orion5x_tclk;
...@@ -283,7 +326,7 @@ void __init orion5x_init(void) ...@@ -283,7 +326,7 @@ void __init orion5x_init(void)
/* /*
* Setup Orion address map * Setup Orion address map
*/ */
orion5x_setup_cpu_mbus_bridge(); orion5x_setup_wins();
/* Setup root of clk tree */ /* Setup root of clk tree */
clk_init(); clk_init();
......
...@@ -17,18 +17,7 @@ void clk_init(void); ...@@ -17,18 +17,7 @@ void clk_init(void);
extern int orion5x_tclk; extern int orion5x_tclk;
extern void orion5x_timer_init(void); extern void orion5x_timer_init(void);
/* void orion5x_setup_wins(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_ehci0_init(void); void orion5x_ehci0_init(void);
void orion5x_ehci1_init(void); void orion5x_ehci1_init(void);
......
...@@ -317,8 +317,8 @@ static void __init d2net_init(void) ...@@ -317,8 +317,8 @@ static void __init d2net_init(void)
d2net_sata_power_init(); d2net_sata_power_init();
orion5x_sata_init(&d2net_sata_data); orion5x_sata_init(&d2net_sata_data);
orion5x_setup_dev_boot_win(D2NET_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", D2NET_NOR_BOOT_BASE,
D2NET_NOR_BOOT_SIZE); D2NET_NOR_BOOT_SIZE);
platform_device_register(&d2net_nor_flash); platform_device_register(&d2net_nor_flash);
platform_device_register(&d2net_gpio_buttons); platform_device_register(&d2net_gpio_buttons);
......
...@@ -340,16 +340,19 @@ static void __init db88f5281_init(void) ...@@ -340,16 +340,19 @@ static void __init db88f5281_init(void)
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_uart1_init(); orion5x_uart1_init();
orion5x_setup_dev_boot_win(DB88F5281_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", DB88F5281_NOR_BOOT_BASE,
DB88F5281_NOR_BOOT_SIZE); DB88F5281_NOR_BOOT_SIZE);
platform_device_register(&db88f5281_boot_flash); 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); 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); platform_device_register(&db88f5281_nand_flash);
i2c_register_board_info(0, &db88f5281_i2c_rtc, 1); i2c_register_board_info(0, &db88f5281_i2c_rtc, 1);
......
...@@ -611,7 +611,8 @@ static void __init dns323_init(void) ...@@ -611,7 +611,8 @@ static void __init dns323_init(void)
/* setup flash mapping /* setup flash mapping
* CS3 holds a 8 MB Spansion S29GL064M90TFIR4 * 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); platform_device_register(&dns323_nor_flash);
/* Sort out LEDs, Buttons and i2c devices */ /* Sort out LEDs, Buttons and i2c devices */
......
...@@ -154,8 +154,8 @@ void __init edmini_v2_init(void) ...@@ -154,8 +154,8 @@ void __init edmini_v2_init(void)
orion5x_ehci0_init(); orion5x_ehci0_init();
orion5x_eth_init(&edmini_v2_eth_data); orion5x_eth_init(&edmini_v2_eth_data);
orion5x_setup_dev_boot_win(EDMINI_V2_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", EDMINI_V2_NOR_BOOT_BASE,
EDMINI_V2_NOR_BOOT_SIZE); EDMINI_V2_NOR_BOOT_SIZE);
platform_device_register(&edmini_v2_nor_flash); platform_device_register(&edmini_v2_nor_flash);
pr_notice("edmini_v2: USB device port, flash write and power-off " pr_notice("edmini_v2: USB device port, flash write and power-off "
......
...@@ -66,8 +66,10 @@ ...@@ -66,8 +66,10 @@
* Orion Registers Map * 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_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_PHYS_BASE (ORION5X_REGS_PHYS_BASE + 0x10000)
#define ORION5X_DEV_BUS_VIRT_BASE (ORION5X_REGS_VIRT_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)) #define ORION5X_DEV_BUS_REG(x) (ORION5X_DEV_BUS_VIRT_BASE + (x))
...@@ -81,6 +83,8 @@ ...@@ -81,6 +83,8 @@
#define ORION5X_BRIDGE_VIRT_BASE (ORION5X_REGS_VIRT_BASE + 0x20000) #define ORION5X_BRIDGE_VIRT_BASE (ORION5X_REGS_VIRT_BASE + 0x20000)
#define ORION5X_BRIDGE_PHYS_BASE (ORION5X_REGS_PHYS_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) #define ORION5X_PCI_VIRT_BASE (ORION5X_REGS_VIRT_BASE + 0x30000)
......
...@@ -359,13 +359,13 @@ static void __init kurobox_pro_init(void) ...@@ -359,13 +359,13 @@ static void __init kurobox_pro_init(void)
orion5x_uart1_init(); orion5x_uart1_init();
orion5x_xor_init(); orion5x_xor_init();
orion5x_setup_dev_boot_win(KUROBOX_PRO_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", KUROBOX_PRO_NOR_BOOT_BASE,
KUROBOX_PRO_NOR_BOOT_SIZE); KUROBOX_PRO_NOR_BOOT_SIZE);
platform_device_register(&kurobox_pro_nor_flash); platform_device_register(&kurobox_pro_nor_flash);
if (machine_is_kurobox_pro()) { if (machine_is_kurobox_pro()) {
orion5x_setup_dev0_win(KUROBOX_PRO_NAND_BASE, mvebu_mbus_add_window("devbus-cs0", KUROBOX_PRO_NAND_BASE,
KUROBOX_PRO_NAND_SIZE); KUROBOX_PRO_NAND_SIZE);
platform_device_register(&kurobox_pro_nand_flash); platform_device_register(&kurobox_pro_nand_flash);
} }
......
...@@ -294,8 +294,8 @@ static void __init lschl_init(void) ...@@ -294,8 +294,8 @@ static void __init lschl_init(void)
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_xor_init(); orion5x_xor_init();
orion5x_setup_dev_boot_win(LSCHL_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", LSCHL_NOR_BOOT_BASE,
LSCHL_NOR_BOOT_SIZE); LSCHL_NOR_BOOT_SIZE);
platform_device_register(&lschl_nor_flash); platform_device_register(&lschl_nor_flash);
platform_device_register(&lschl_leds); platform_device_register(&lschl_leds);
......
...@@ -243,8 +243,8 @@ static void __init ls_hgl_init(void) ...@@ -243,8 +243,8 @@ static void __init ls_hgl_init(void)
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_xor_init(); orion5x_xor_init();
orion5x_setup_dev_boot_win(LS_HGL_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", LS_HGL_NOR_BOOT_BASE,
LS_HGL_NOR_BOOT_SIZE); LS_HGL_NOR_BOOT_SIZE);
platform_device_register(&ls_hgl_nor_flash); platform_device_register(&ls_hgl_nor_flash);
platform_device_register(&ls_hgl_button_device); platform_device_register(&ls_hgl_button_device);
......
...@@ -244,8 +244,8 @@ static void __init lsmini_init(void) ...@@ -244,8 +244,8 @@ static void __init lsmini_init(void)
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_xor_init(); orion5x_xor_init();
orion5x_setup_dev_boot_win(LSMINI_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", LSMINI_NOR_BOOT_BASE,
LSMINI_NOR_BOOT_SIZE); LSMINI_NOR_BOOT_SIZE);
platform_device_register(&lsmini_nor_flash); platform_device_register(&lsmini_nor_flash);
platform_device_register(&lsmini_button_device); platform_device_register(&lsmini_button_device);
......
...@@ -241,7 +241,8 @@ static void __init mss2_init(void) ...@@ -241,7 +241,8 @@ static void __init mss2_init(void)
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_xor_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_nor_flash);
platform_device_register(&mss2_button_device); platform_device_register(&mss2_button_device);
......
...@@ -204,7 +204,8 @@ static void __init mv2120_init(void) ...@@ -204,7 +204,8 @@ static void __init mv2120_init(void)
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_xor_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_nor_flash);
platform_device_register(&mv2120_button_device); platform_device_register(&mv2120_button_device);
......
...@@ -397,8 +397,8 @@ static void __init net2big_init(void) ...@@ -397,8 +397,8 @@ static void __init net2big_init(void)
net2big_sata_power_init(); net2big_sata_power_init();
orion5x_sata_init(&net2big_sata_data); orion5x_sata_init(&net2big_sata_data);
orion5x_setup_dev_boot_win(NET2BIG_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", NET2BIG_NOR_BOOT_BASE,
NET2BIG_NOR_BOOT_SIZE); NET2BIG_NOR_BOOT_SIZE);
platform_device_register(&net2big_nor_flash); platform_device_register(&net2big_nor_flash);
platform_device_register(&net2big_gpio_buttons); platform_device_register(&net2big_gpio_buttons);
......
...@@ -157,8 +157,11 @@ static int __init pcie_setup(struct pci_sys_data *sys) ...@@ -157,8 +157,11 @@ static int __init pcie_setup(struct pci_sys_data *sys)
if (dev == MV88F5181_DEV_ID || dev == MV88F5182_DEV_ID) { if (dev == MV88F5181_DEV_ID || dev == MV88F5182_DEV_ID) {
printk(KERN_NOTICE "Applying Orion-1/Orion-NAS PCIe config " printk(KERN_NOTICE "Applying Orion-1/Orion-NAS PCIe config "
"read transaction workaround\n"); "read transaction workaround\n");
orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE, mvebu_mbus_add_window_remap_flags("pcie0.0",
ORION5X_PCIE_WA_SIZE); ORION5X_PCIE_WA_PHYS_BASE,
ORION5X_PCIE_WA_SIZE,
MVEBU_MBUS_NO_REMAP,
MVEBU_MBUS_PCI_WA);
pcie_ops.read = pcie_rd_conf_wa; pcie_ops.read = pcie_rd_conf_wa;
} }
......
...@@ -123,8 +123,8 @@ static void __init rd88f5181l_fxo_init(void) ...@@ -123,8 +123,8 @@ static void __init rd88f5181l_fxo_init(void)
orion5x_eth_switch_init(&rd88f5181l_fxo_switch_plat_data, NO_IRQ); orion5x_eth_switch_init(&rd88f5181l_fxo_switch_plat_data, NO_IRQ);
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", RD88F5181L_FXO_NOR_BOOT_BASE,
RD88F5181L_FXO_NOR_BOOT_SIZE); RD88F5181L_FXO_NOR_BOOT_SIZE);
platform_device_register(&rd88f5181l_fxo_nor_boot_flash); platform_device_register(&rd88f5181l_fxo_nor_boot_flash);
} }
......
...@@ -130,8 +130,8 @@ static void __init rd88f5181l_ge_init(void) ...@@ -130,8 +130,8 @@ static void __init rd88f5181l_ge_init(void)
orion5x_i2c_init(); orion5x_i2c_init();
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_setup_dev_boot_win(RD88F5181L_GE_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", RD88F5181L_GE_NOR_BOOT_BASE,
RD88F5181L_GE_NOR_BOOT_SIZE); RD88F5181L_GE_NOR_BOOT_SIZE);
platform_device_register(&rd88f5181l_ge_nor_boot_flash); platform_device_register(&rd88f5181l_ge_nor_boot_flash);
i2c_register_board_info(0, &rd88f5181l_ge_i2c_rtc, 1); i2c_register_board_info(0, &rd88f5181l_ge_i2c_rtc, 1);
......
...@@ -264,10 +264,11 @@ static void __init rd88f5182_init(void) ...@@ -264,10 +264,11 @@ static void __init rd88f5182_init(void)
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_xor_init(); orion5x_xor_init();
orion5x_setup_dev_boot_win(RD88F5182_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", RD88F5182_NOR_BOOT_BASE,
RD88F5182_NOR_BOOT_SIZE); 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_nor_flash);
platform_device_register(&rd88f5182_gpio_leds); platform_device_register(&rd88f5182_gpio_leds);
......
...@@ -329,8 +329,8 @@ static void __init tsp2_init(void) ...@@ -329,8 +329,8 @@ static void __init tsp2_init(void)
/* /*
* Configure peripherals. * Configure peripherals.
*/ */
orion5x_setup_dev_boot_win(TSP2_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", TSP2_NOR_BOOT_BASE,
TSP2_NOR_BOOT_SIZE); TSP2_NOR_BOOT_SIZE);
platform_device_register(&tsp2_nor_flash); platform_device_register(&tsp2_nor_flash);
orion5x_ehci0_init(); orion5x_ehci0_init();
......
...@@ -286,8 +286,8 @@ static void __init qnap_ts209_init(void) ...@@ -286,8 +286,8 @@ static void __init qnap_ts209_init(void)
/* /*
* Configure peripherals. * Configure peripherals.
*/ */
orion5x_setup_dev_boot_win(QNAP_TS209_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", QNAP_TS209_NOR_BOOT_BASE,
QNAP_TS209_NOR_BOOT_SIZE); QNAP_TS209_NOR_BOOT_SIZE);
platform_device_register(&qnap_ts209_nor_flash); platform_device_register(&qnap_ts209_nor_flash);
orion5x_ehci0_init(); orion5x_ehci0_init();
......
...@@ -277,8 +277,8 @@ static void __init qnap_ts409_init(void) ...@@ -277,8 +277,8 @@ static void __init qnap_ts409_init(void)
/* /*
* Configure peripherals. * Configure peripherals.
*/ */
orion5x_setup_dev_boot_win(QNAP_TS409_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", QNAP_TS409_NOR_BOOT_BASE,
QNAP_TS409_NOR_BOOT_SIZE); QNAP_TS409_NOR_BOOT_SIZE);
platform_device_register(&qnap_ts409_nor_flash); platform_device_register(&qnap_ts409_nor_flash);
orion5x_ehci0_init(); orion5x_ehci0_init();
......
...@@ -127,8 +127,8 @@ static void __init wnr854t_init(void) ...@@ -127,8 +127,8 @@ static void __init wnr854t_init(void)
orion5x_eth_switch_init(&wnr854t_switch_plat_data, NO_IRQ); orion5x_eth_switch_init(&wnr854t_switch_plat_data, NO_IRQ);
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_setup_dev_boot_win(WNR854T_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", WNR854T_NOR_BOOT_BASE,
WNR854T_NOR_BOOT_SIZE); WNR854T_NOR_BOOT_SIZE);
platform_device_register(&wnr854t_nor_flash); platform_device_register(&wnr854t_nor_flash);
} }
......
...@@ -213,8 +213,8 @@ static void __init wrt350n_v2_init(void) ...@@ -213,8 +213,8 @@ static void __init wrt350n_v2_init(void)
orion5x_eth_switch_init(&wrt350n_v2_switch_plat_data, NO_IRQ); orion5x_eth_switch_init(&wrt350n_v2_switch_plat_data, NO_IRQ);
orion5x_uart0_init(); orion5x_uart0_init();
orion5x_setup_dev_boot_win(WRT350N_V2_NOR_BOOT_BASE, mvebu_mbus_add_window("devbus-boot", WRT350N_V2_NOR_BOOT_BASE,
WRT350N_V2_NOR_BOOT_SIZE); WRT350N_V2_NOR_BOOT_SIZE);
platform_device_register(&wrt350n_v2_nor_flash); platform_device_register(&wrt350n_v2_nor_flash);
platform_device_register(&wrt350n_v2_leds); platform_device_register(&wrt350n_v2_leds);
platform_device_register(&wrt350n_v2_button_device); platform_device_register(&wrt350n_v2_button_device);
......
...@@ -26,6 +26,25 @@ ...@@ -26,6 +26,25 @@
#include <mach/clock.h> #include <mach/clock.h>
#include <mach/common.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 MD(nr) BIT(nr)
#define FRQMR IOMEM(0xffc80014) #define FRQMR IOMEM(0xffc80014)
...@@ -93,7 +112,7 @@ static struct clk *main_clks[] = { ...@@ -93,7 +112,7 @@ static struct clk *main_clks[] = {
}; };
enum { MSTP323, MSTP322, MSTP321, MSTP320, enum { MSTP323, MSTP322, MSTP321, MSTP320,
MSTP115, MSTP115, MSTP114,
MSTP103, MSTP101, MSTP100, MSTP103, MSTP101, MSTP100,
MSTP030, MSTP030,
MSTP029, MSTP028, MSTP027, MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021, MSTP029, MSTP028, MSTP027, MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
...@@ -107,6 +126,7 @@ static struct clk mstp_clks[MSTP_NR] = { ...@@ -107,6 +126,7 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP321] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 21, 0), /* SDHI2 */ [MSTP321] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 21, 0), /* SDHI2 */
[MSTP320] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 20, 0), /* SDHI3 */ [MSTP320] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 20, 0), /* SDHI3 */
[MSTP115] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 15, 0), /* SATA */ [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 */ [MSTP103] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 3, 0), /* DU */
[MSTP101] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 1, 0), /* USB2 */ [MSTP101] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 1, 0), /* USB2 */
[MSTP100] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 0, 0), /* USB0/1 */ [MSTP100] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 0, 0), /* USB0/1 */
...@@ -143,6 +163,7 @@ static struct clk_lookup lookups[] = { ...@@ -143,6 +163,7 @@ static struct clk_lookup lookups[] = {
/* MSTP32 clocks */ /* MSTP32 clocks */
CLKDEV_DEV_ID("sata_rcar", &mstp_clks[MSTP115]), /* SATA */ CLKDEV_DEV_ID("sata_rcar", &mstp_clks[MSTP115]), /* SATA */
CLKDEV_DEV_ID("fc600000.sata", &mstp_clks[MSTP115]), /* SATA w/DT */ 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("ehci-platform.1", &mstp_clks[MSTP101]), /* USB EHCI port2 */
CLKDEV_DEV_ID("ohci-platform.1", &mstp_clks[MSTP101]), /* USB OHCI 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 */ CLKDEV_DEV_ID("ehci-platform.0", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/sh_clk.h> #include <linux/sh_clk.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/sh_eth.h>
struct platform_device; struct platform_device;
...@@ -31,6 +32,7 @@ extern void r8a7779_earlytimer_init(void); ...@@ -31,6 +32,7 @@ extern void r8a7779_earlytimer_init(void);
extern void r8a7779_add_early_devices(void); extern void r8a7779_add_early_devices(void);
extern void r8a7779_add_standard_devices(void); extern void r8a7779_add_standard_devices(void);
extern void r8a7779_add_standard_devices_dt(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_clock_init(void);
extern void r8a7779_pinmux_init(void); extern void r8a7779_pinmux_init(void);
extern void r8a7779_pm_init(void); extern void r8a7779_pm_init(void);
......
/* /*
* r8a7779 processor support * r8a7779 processor support
* *
* Copyright (C) 2011 Renesas Solutions Corp. * Copyright (C) 2011, 2013 Renesas Solutions Corp.
* Copyright (C) 2011 Magnus Damm * Copyright (C) 2011 Magnus Damm
* Copyright (C) 2013 Cogent Embedded, Inc.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -393,6 +394,18 @@ static struct platform_device sata_device = { ...@@ -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 = { static struct platform_device *r8a7779_devices_dt[] __initdata = {
&scif0_device, &scif0_device,
&scif1_device, &scif1_device,
...@@ -428,6 +441,14 @@ void __init r8a7779_add_standard_devices(void) ...@@ -428,6 +441,14 @@ void __init r8a7779_add_standard_devices(void)
ARRAY_SIZE(r8a7779_late_devices)); 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 */ /* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */
void __init __weak r8a7779_register_twd(void) { } void __init __weak r8a7779_register_twd(void) { }
......
...@@ -10,6 +10,7 @@ config ARCH_ZYNQ ...@@ -10,6 +10,7 @@ config ARCH_ZYNQ
select ICST select ICST
select MIGHT_HAVE_CACHE_L2X0 select MIGHT_HAVE_CACHE_L2X0
select USE_OF select USE_OF
select HAVE_SMP
select SPARSE_IRQ select SPARSE_IRQ
select CADENCE_TTC_TIMER select CADENCE_TTC_TIMER
help help
......
...@@ -3,4 +3,8 @@ ...@@ -3,4 +3,8 @@
# #
# Common support # 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
...@@ -33,20 +33,23 @@ ...@@ -33,20 +33,23 @@
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/smp_scu.h>
#include <asm/hardware/cache-l2x0.h> #include <asm/hardware/cache-l2x0.h>
#include "common.h" #include "common.h"
void __iomem *zynq_scu_base;
static struct of_device_id zynq_of_bus_ids[] __initdata = { static struct of_device_id zynq_of_bus_ids[] __initdata = {
{ .compatible = "simple-bus", }, { .compatible = "simple-bus", },
{} {}
}; };
/** /**
* xilinx_init_machine() - System specific initialization, intended to be * zynq_init_machine - System specific initialization, intended to be
* called from board specific initialization. * 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 * 64KB way size, 8-way associativity, parity disabled
...@@ -56,50 +59,56 @@ static void __init xilinx_init_machine(void) ...@@ -56,50 +59,56 @@ static void __init xilinx_init_machine(void)
of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL); of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL);
} }
#define SCU_PERIPH_PHYS 0xF8F00000 static void __init zynq_timer_init(void)
#define SCU_PERIPH_SIZE SZ_8K {
#define SCU_PERIPH_VIRT (VMALLOC_END - SCU_PERIPH_SIZE) zynq_slcr_init();
clocksource_of_init();
}
static struct map_desc scu_desc __initdata = { static struct map_desc zynq_cortex_a9_scu_map __initdata = {
.virtual = SCU_PERIPH_VIRT, .length = SZ_256,
.pfn = __phys_to_pfn(SCU_PERIPH_PHYS), .type = MT_DEVICE,
.length = SCU_PERIPH_SIZE,
.type = MT_DEVICE,
}; };
static void __init xilinx_zynq_timer_init(void) static void __init zynq_scu_map_io(void)
{ {
struct device_node *np; unsigned long base;
void __iomem *slcr;
np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr");
slcr = of_iomap(np, 0);
WARN_ON(!slcr);
xilinx_zynq_clocks_init(slcr); base = scu_a9_get_base();
zynq_cortex_a9_scu_map.pfn = __phys_to_pfn(base);
clocksource_of_init(); /* 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(); 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-zc702",
"xlnx,zynq-7000", "xlnx,zynq-7000",
NULL NULL
}; };
MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") 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_irq = irqchip_init,
.init_machine = xilinx_init_machine, .init_machine = zynq_init_machine,
.init_time = xilinx_zynq_timer_init, .init_time = zynq_timer_init,
.dt_compat = xilinx_dt_match, .dt_compat = zynq_dt_match,
.restart = zynq_system_reset,
MACHINE_END MACHINE_END
...@@ -17,4 +17,24 @@ ...@@ -17,4 +17,24 @@
#ifndef __MACH_ZYNQ_COMMON_H__ #ifndef __MACH_ZYNQ_COMMON_H__
#define __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 #endif
/*
* 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)
/*
* 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);
}
/*
* 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
};
/*
* 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;
}
...@@ -3,12 +3,6 @@ ...@@ -3,12 +3,6 @@
# #
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include 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 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) += irq.o pcie.o time.o common.o mpp.o
obj-$(CONFIG_PLAT_ORION_LEGACY) += $(orion-gpio-y) obj-$(CONFIG_PLAT_ORION_LEGACY) += $(orion-gpio-y)
/*
* 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;
}
...@@ -439,6 +439,64 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) ...@@ -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, void __init orion_gpio_init(struct device_node *np,
int gpio_base, int ngpio, int gpio_base, int ngpio,
void __iomem *base, int mask_offset, void __iomem *base, int mask_offset,
...@@ -471,6 +529,7 @@ void __init orion_gpio_init(struct device_node *np, ...@@ -471,6 +529,7 @@ void __init orion_gpio_init(struct device_node *np,
#ifdef CONFIG_OF #ifdef CONFIG_OF
ochip->chip.of_node = np; ochip->chip.of_node = np;
#endif #endif
ochip->chip.dbg_show = orion_gpio_dbg_show;
spin_lock_init(&ochip->lock); spin_lock_init(&ochip->lock);
ochip->base = (void __iomem *)base; ochip->base = (void __iomem *)base;
......
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
menu "Bus devices" 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 config OMAP_OCP2SCP
tristate "OMAP OCP2SCP DRIVER" tristate "OMAP OCP2SCP DRIVER"
depends on ARCH_OMAP2PLUS depends on ARCH_OMAP2PLUS
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# Makefile for the bus drivers. # Makefile for the bus drivers.
# #
obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
# Interconnect bus driver for OMAP SoCs. # Interconnect bus driver for OMAP SoCs.
......
/*
* 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;
}
...@@ -2552,7 +2552,7 @@ static const char * const intc_groups[] = { ...@@ -2552,7 +2552,7 @@ static const char * const intc_groups[] = {
"intc_irq2", "intc_irq2",
"intc_irq2_b", "intc_irq2_b",
"intc_irq3", "intc_irq3",
"intc_irq4_b", "intc_irq3_b",
}; };
static const char * const lbsc_groups[] = { static const char * const lbsc_groups[] = {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/reset.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
...@@ -661,7 +662,7 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel) ...@@ -661,7 +662,7 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
} }
EXPORT_SYMBOL_GPL(ipu_idmac_disable_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; unsigned long timeout;
...@@ -1105,7 +1106,12 @@ static int ipu_probe(struct platform_device *pdev) ...@@ -1105,7 +1106,12 @@ static int ipu_probe(struct platform_device *pdev)
if (ret) if (ret)
goto out_failed_irq; 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) if (ret)
goto out_failed_reset; goto out_failed_reset;
...@@ -1131,8 +1137,8 @@ static int ipu_probe(struct platform_device *pdev) ...@@ -1131,8 +1137,8 @@ static int ipu_probe(struct platform_device *pdev)
failed_add_clients: failed_add_clients:
ipu_submodules_exit(ipu); ipu_submodules_exit(ipu);
failed_submodules_init: failed_submodules_init:
ipu_irq_exit(ipu);
out_failed_reset: out_failed_reset:
ipu_irq_exit(ipu);
out_failed_irq: out_failed_irq:
clk_disable_unprepare(ipu->clk); clk_disable_unprepare(ipu->clk);
failed_clk_get: failed_clk_get:
......
...@@ -32,6 +32,20 @@ struct mbus_dram_target_info ...@@ -32,6 +32,20 @@ struct mbus_dram_target_info
} cs[4]; } 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 * The Marvell mbus is to be found only on SOCs from the Orion family
* at the moment. Provide a dummy stub for other architectures. * 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) ...@@ -44,4 +58,15 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void)
return NULL; return NULL;
} }
#endif #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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment