mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
ARM: SoC driver updates
Driver updates for ARM SoCs.
A handful of driver changes this time around. The larger changes are:
- Reset drivers for hi3660 and zx2967
- AHCI driver for Davinci, acked by Tejun and brought in here due to
platform dependencies
- Cleanups of atmel-ebi (External Bus Interface)
- Tweaks for Rockchip GRF (General Register File) usage (kitchensink misc
register range on the SoCs)
- PM domains changes for support of two new ZTE SoCs (zx296718 and zx2967)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAABAgAGBQJYrM7/AAoJEIwa5zzehBx3qisP/18NwvbYvC3rMza7k+TEU66n
vuEF9KW5GhUpQPbNIsTer5qHhC7ZgL7RoR/H7mpZcCxfhYiNXuUaOv8TMGK+WTLQ
HH6QTs4mARLh1IrRcog1hoElzzqMVxaQgODeaaG1DcPvTqHWsQurbXsf17tCQOri
nWKyxFpLNlu0kktkGb5JWrM4XBjU9KsW7LME9H86wG8HmB6+mcT5ddeYwW5nD8cG
txXgmMjdTEKcpbeTg3cAzL4504auhIl4R9uK+8dc1sw+e9T0nXNDS9IkmLPwWtSR
u8q6zQ3zReoDw4jGUgPP0ILHudfQsiMdWS+P2hw/krpbtLlQ+irHDVa1VA3NLiUT
9aG9cNTYRMo3ct22YEeWsnAC04XOxpCsqHTR+UWuZaBmf3eoMIXnsafTuwLzqKlQ
Ent/4eFPInMAzDH8Kaf1Hh0918qkgF2bNlshem11TccQKvHP+qCoHk6mKGxwEj5k
E1UEG4S6k6zNqjLwmTBBbk8sLMl/WVo6RMSMz+JflatgPmVZco4EX2O73iKGAJVU
5GfHIUG9Yl4+aTIUORu59cWxOCApK0kqERrFKe412BMurXlLfqVcr/H2tiiuWnn1
cEJ9d+uBd8IxTIQX0iEYGUAkX97mhxGUYdqGQuGJSV+MOfWX1zNP1sI4EscLGKQj
sDDZScCaguM4xE20Jum1
=od7u
-----END PGP SIGNATURE-----
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Arnd Bergmann:
"Driver updates for ARM SoCs.
A handful of driver changes this time around. The larger changes are:
- Reset drivers for hi3660 and zx2967
- AHCI driver for Davinci, acked by Tejun and brought in here due to
platform dependencies
- Cleanups of atmel-ebi (External Bus Interface)
- Tweaks for Rockchip GRF (General Register File) usage (kitchensink
misc register range on the SoCs)
- PM domains changes for support of two new ZTE SoCs (zx296718 and
zx2967)"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (53 commits)
soc: samsung: pmu: Add register defines for pad retention control
reset: make zx2967 explicitly non-modular
reset: core: fix reset_control_put
soc: samsung: pm_domains: Read domain name from the new label property
soc: samsung: pm_domains: Remove message about failed memory allocation
soc: samsung: pm_domains: Remove unused name field
soc: samsung: pm_domains: Use full names in subdomains registration log
sata: ahci-da850: un-hardcode the MPY bits
sata: ahci-da850: add a workaround for controller instability
sata: ahci: export ahci_do_hardreset() locally
sata: ahci-da850: implement a workaround for the softreset quirk
sata: ahci-da850: add device tree match table
sata: ahci-da850: get the sata clock using a connection id
soc: samsung: pmu: Remove duplicated define for ARM_L2_OPTION register
memory: atmel-ebi: Enable the SMC clock if specified
soc: samsung: pmu: Remove unused and duplicated defines
memory: atmel-ebi: Properly handle multiple reference to the same CS
memory: atmel-ebi: Fix the test to enable generic SMC logic
soc: samsung: pm_domains: Add new Exynos5433 compatible
soc: samsung: pmu: Add dummy support for Exynos5433 SoC
...
This commit is contained in:
commit
b2e3c4319d
54 changed files with 1481 additions and 288 deletions
|
|
@ -6,12 +6,15 @@ to gate power to one or more peripherals on the processor.
|
|||
Required Properties:
|
||||
- compatible: should be one of the following.
|
||||
* samsung,exynos4210-pd - for exynos4210 type power domain.
|
||||
* samsung,exynos5433-pd - for exynos5433 type power domain.
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #power-domain-cells: number of cells in power domain specifier;
|
||||
must be 0.
|
||||
|
||||
Optional Properties:
|
||||
- label: Human readable string with domain name. Will be visible in userspace
|
||||
to let user to distinguish between multiple domains in SoC.
|
||||
- clocks: List of clock handles. The parent clocks of the input clocks to the
|
||||
devices in this power domain are set to oscclk before power gating
|
||||
and restored back after powering on a domain. This is required for
|
||||
|
|
@ -38,6 +41,7 @@ Example:
|
|||
compatible = "samsung,exynos4210-pd";
|
||||
reg = <0x10023C00 0x10>;
|
||||
#power-domain-cells = <0>;
|
||||
label = "LCD0";
|
||||
};
|
||||
|
||||
mfc_pd: power-domain@10044060 {
|
||||
|
|
@ -46,6 +50,7 @@ Example:
|
|||
clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_USER_ACLK333>;
|
||||
clock-names = "oscclk", "clk0";
|
||||
#power-domain-cells = <0>;
|
||||
label = "MFC";
|
||||
};
|
||||
|
||||
See Documentation/devicetree/bindings/power/power_domain.txt for description
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
Hisilicon System Reset Controller
|
||||
======================================
|
||||
|
||||
Please also refer to reset.txt in this directory for common reset
|
||||
controller binding usage.
|
||||
|
||||
The reset controller registers are part of the system-ctl block on
|
||||
hi3660 SoC.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be
|
||||
"hisilicon,hi3660-reset"
|
||||
- hisi,rst-syscon: phandle of the reset's syscon.
|
||||
- #reset-cells : Specifies the number of cells needed to encode a
|
||||
reset source. The type shall be a <u32> and the value shall be 2.
|
||||
|
||||
Cell #1 : offset of the reset assert control
|
||||
register from the syscon register base
|
||||
offset + 4: deassert control register
|
||||
offset + 8: status control register
|
||||
Cell #2 : bit position of the reset in the reset control register
|
||||
|
||||
Example:
|
||||
iomcu: iomcu@ffd7e000 {
|
||||
compatible = "hisilicon,hi3660-iomcu", "syscon";
|
||||
reg = <0x0 0xffd7e000 0x0 0x1000>;
|
||||
};
|
||||
|
||||
iomcu_rst: iomcu_rst_controller {
|
||||
compatible = "hisilicon,hi3660-reset";
|
||||
hisi,rst-syscon = <&iomcu>;
|
||||
#reset-cells = <2>;
|
||||
};
|
||||
|
||||
Specifying reset lines connected to IP modules
|
||||
==============================================
|
||||
example:
|
||||
|
||||
i2c0: i2c@..... {
|
||||
...
|
||||
resets = <&iomcu_rst 0x20 3>; /* offset: 0x20; bit: 3 */
|
||||
...
|
||||
};
|
||||
|
|
@ -63,7 +63,7 @@ Example:
|
|||
--------
|
||||
The following example demonstrates a syscon node, the reset controller node
|
||||
using the syscon node, and a consumer (a DSP device) on the TI Keystone 2
|
||||
Edison SoC.
|
||||
66AK2E SoC.
|
||||
|
||||
/ {
|
||||
soc {
|
||||
|
|
@ -71,13 +71,13 @@ Edison SoC.
|
|||
compatible = "syscon", "simple-mfd";
|
||||
reg = <0x02350000 0x1000>;
|
||||
|
||||
pscrst: psc-reset {
|
||||
pscrst: reset-controller {
|
||||
compatible = "ti,k2e-pscrst", "ti,syscon-reset";
|
||||
#reset-cells = <1>;
|
||||
|
||||
ti,reset-bits = <
|
||||
0xa3c 8 0xa3c 8 0x83c 8 (ASSERT_SET|DEASSERT_CLEAR|STATUS_SET) /* 0: pcrst-dsp0 */
|
||||
0xa40 5 0xa44 3 0 0 (ASSERT_SET|DEASSERT_CLEAR|STATUS_NONE) /* 1: pcrst-example */
|
||||
0xa3c 8 0xa3c 8 0x83c 8 (ASSERT_CLEAR | DEASSERT_SET | STATUS_CLEAR) /* 0: dsp0 */
|
||||
0xa40 5 0xa44 3 0 0 (ASSERT_SET | DEASSERT_CLEAR | STATUS_NONE) /* 1: example */
|
||||
>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ System reset
|
|||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-reset" - for sLD3 SoC.
|
||||
"socionext,uniphier-ld4-reset" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-reset" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-reset" - for sLD8 SoC.
|
||||
"socionext,uniphier-pro5-reset" - for Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-reset" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-reset" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-reset" - for LD20 SoC.
|
||||
"socionext,uniphier-sld3-reset" - for sLD3 SoC
|
||||
"socionext,uniphier-ld4-reset" - for LD4 SoC
|
||||
"socionext,uniphier-pro4-reset" - for Pro4 SoC
|
||||
"socionext,uniphier-sld8-reset" - for sLD8 SoC
|
||||
"socionext,uniphier-pro5-reset" - for Pro5 SoC
|
||||
"socionext,uniphier-pxs2-reset" - for PXs2/LD6b SoC
|
||||
"socionext,uniphier-ld11-reset" - for LD11 SoC
|
||||
"socionext,uniphier-ld20-reset" - for LD20 SoC
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
|
@ -37,14 +37,15 @@ Media I/O (MIO) reset, SD reset
|
|||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-mio-reset" - for sLD3 SoC.
|
||||
"socionext,uniphier-ld4-mio-reset" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-mio-reset" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-mio-reset" - for sLD8 SoC.
|
||||
"socionext,uniphier-pro5-sd-reset" - for Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-sd-reset" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-mio-reset" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-sd-reset" - for LD20 SoC.
|
||||
"socionext,uniphier-sld3-mio-reset" - for sLD3 SoC
|
||||
"socionext,uniphier-ld4-mio-reset" - for LD4 SoC
|
||||
"socionext,uniphier-pro4-mio-reset" - for Pro4 SoC
|
||||
"socionext,uniphier-sld8-mio-reset" - for sLD8 SoC
|
||||
"socionext,uniphier-pro5-sd-reset" - for Pro5 SoC
|
||||
"socionext,uniphier-pxs2-sd-reset" - for PXs2/LD6b SoC
|
||||
"socionext,uniphier-ld11-mio-reset" - for LD11 SoC (MIO)
|
||||
"socionext,uniphier-ld11-sd-reset" - for LD11 SoC (SD)
|
||||
"socionext,uniphier-ld20-sd-reset" - for LD20 SoC
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
|
@ -68,13 +69,13 @@ Peripheral reset
|
|||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-ld4-peri-reset" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-peri-reset" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-peri-reset" - for sLD8 SoC.
|
||||
"socionext,uniphier-pro5-peri-reset" - for Pro5 SoC.
|
||||
"socionext,uniphier-pxs2-peri-reset" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-peri-reset" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-peri-reset" - for LD20 SoC.
|
||||
"socionext,uniphier-ld4-peri-reset" - for LD4 SoC
|
||||
"socionext,uniphier-pro4-peri-reset" - for Pro4 SoC
|
||||
"socionext,uniphier-sld8-peri-reset" - for sLD8 SoC
|
||||
"socionext,uniphier-pro5-peri-reset" - for Pro5 SoC
|
||||
"socionext,uniphier-pxs2-peri-reset" - for PXs2/LD6b SoC
|
||||
"socionext,uniphier-ld11-peri-reset" - for LD11 SoC
|
||||
"socionext,uniphier-ld20-peri-reset" - for LD20 SoC
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
|
|
|||
20
Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
Normal file
20
Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
ZTE zx2967 SoCs Reset Controller
|
||||
=======================================
|
||||
|
||||
Please also refer to reset.txt in this directory for common reset
|
||||
controller binding usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following.
|
||||
* zte,zx296718-reset
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #reset-cells: must be 1.
|
||||
|
||||
example:
|
||||
|
||||
reset: reset-controller@1461060 {
|
||||
compatible = "zte,zx296718-reset";
|
||||
reg = <0x01461060 0x8>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
|
@ -5,11 +5,13 @@ is composed of many registers for system control.
|
|||
|
||||
From RK3368 SoCs, the GRF is divided into two sections,
|
||||
- GRF, used for general non-secure system,
|
||||
- SGRF, used for general secure system,
|
||||
- PMUGRF, used for always on system
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: GRF should be one of the followings
|
||||
- "rockchip,rk3036-grf", "syscon": for rk3036
|
||||
- "rockchip,rk3066-grf", "syscon": for rk3066
|
||||
- "rockchip,rk3188-grf", "syscon": for rk3188
|
||||
- "rockchip,rk3228-grf", "syscon": for rk3228
|
||||
|
|
@ -19,6 +21,8 @@ Required Properties:
|
|||
- compatible: PMUGRF should be one of the followings
|
||||
- "rockchip,rk3368-pmugrf", "syscon": for rk3368
|
||||
- "rockchip,rk3399-pmugrf", "syscon": for rk3399
|
||||
- compatible: SGRF should be one of the following
|
||||
- "rockchip,rk3288-sgrf", "syscon": for rk3288
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ powered up/down by software based on different application scenes to save power.
|
|||
Required properties for power domain controller:
|
||||
- compatible: Should be one of the following.
|
||||
"rockchip,rk3288-power-controller" - for RK3288 SoCs.
|
||||
"rockchip,rk3328-power-controller" - for RK3328 SoCs.
|
||||
"rockchip,rk3368-power-controller" - for RK3368 SoCs.
|
||||
"rockchip,rk3399-power-controller" - for RK3399 SoCs.
|
||||
- #power-domain-cells: Number of cells in a power-domain specifier.
|
||||
|
|
@ -16,6 +17,7 @@ Required properties for power domain controller:
|
|||
Required properties for power domain sub nodes:
|
||||
- reg: index of the power domain, should use macros in:
|
||||
"include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain.
|
||||
"include/dt-bindings/power/rk3328-power.h" - for RK3328 type power domain.
|
||||
"include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain.
|
||||
"include/dt-bindings/power/rk3399-power.h" - for RK3399 type power domain.
|
||||
- clocks (optional): phandles to clocks which need to be enabled while power domain
|
||||
|
|
@ -90,6 +92,7 @@ containing a phandle to the power device node and an index specifying which
|
|||
power domain to use.
|
||||
The index should use macros in:
|
||||
"include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain.
|
||||
"include/dt-bindings/power/rk3328-power.h" - for rk3328 type power domain.
|
||||
"include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain.
|
||||
"include/dt-bindings/power/rk3399-power.h" - for rk3399 type power domain.
|
||||
|
||||
|
|
|
|||
19
Documentation/devicetree/bindings/soc/zte/pd-2967xx.txt
Normal file
19
Documentation/devicetree/bindings/soc/zte/pd-2967xx.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
* ZTE zx2967 family Power Domains
|
||||
|
||||
zx2967 family includes support for multiple power domains which are used
|
||||
to gate power to one or more peripherals on the processor.
|
||||
|
||||
Required Properties:
|
||||
- compatible: should be one of the following.
|
||||
* zte,zx296718-pcu - for zx296718 power domain.
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #power-domain-cells: Must be 1.
|
||||
|
||||
Example:
|
||||
|
||||
pcu_domain: pcu@117000 {
|
||||
compatible = "zte,zx296718-pcu";
|
||||
reg = <0x00117000 0x1000>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
|
@ -1633,6 +1633,7 @@ F: arch/arm64/boot/dts/qcom/*
|
|||
F: drivers/i2c/busses/i2c-qup.c
|
||||
F: drivers/clk/qcom/
|
||||
F: drivers/pinctrl/qcom/
|
||||
F: drivers/dma/qcom/
|
||||
F: drivers/soc/qcom/
|
||||
F: drivers/spi/spi-qup.c
|
||||
F: drivers/tty/serial/msm_serial.h
|
||||
|
|
@ -1987,12 +1988,18 @@ F: arch/arm/mach-pxa/include/mach/z2.h
|
|||
|
||||
ARM/ZTE ARCHITECTURE
|
||||
M: Jun Nie <jun.nie@linaro.org>
|
||||
M: Baoyou Xie <baoyou.xie@linaro.org>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: arch/arm/mach-zx/
|
||||
F: drivers/clk/zte/
|
||||
F: drivers/reset/reset-zx2967.c
|
||||
F: drivers/soc/zte/
|
||||
F: Documentation/devicetree/bindings/arm/zte.txt
|
||||
F: Documentation/devicetree/bindings/clock/zx296702-clk.txt
|
||||
F: Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
|
||||
F: Documentation/devicetree/bindings/soc/zte/
|
||||
F: include/dt-bindings/soc/zx*.h
|
||||
|
||||
ARM/ZYNQ ARCHITECTURE
|
||||
M: Michal Simek <michal.simek@xilinx.com>
|
||||
|
|
|
|||
|
|
@ -345,9 +345,9 @@ static void exynos5420_pm_prepare(void)
|
|||
if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
|
||||
pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0);
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION);
|
||||
tmp &= ~EXYNOS5_USE_RETENTION;
|
||||
pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
|
||||
tmp = pmu_raw_readl(EXYNOS_L2_OPTION(0));
|
||||
tmp &= ~EXYNOS_L2_USE_RETENTION;
|
||||
pmu_raw_writel(tmp, EXYNOS_L2_OPTION(0));
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
|
||||
tmp |= EXYNOS5420_UFS;
|
||||
|
|
|
|||
|
|
@ -29,13 +29,11 @@
|
|||
#include "core.h"
|
||||
#include "pm.h"
|
||||
|
||||
#define RK3288_GRF_SOC_CON0 0x244
|
||||
#define RK3288_TIMER6_7_PHYS 0xff810000
|
||||
|
||||
static void __init rockchip_timer_init(void)
|
||||
{
|
||||
if (of_machine_is_compatible("rockchip,rk3288")) {
|
||||
struct regmap *grf;
|
||||
void __iomem *reg_base;
|
||||
|
||||
/*
|
||||
|
|
@ -54,16 +52,6 @@ static void __init rockchip_timer_init(void)
|
|||
} else {
|
||||
pr_err("rockchip: could not map timer7 registers\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable auto jtag/sdmmc switching that causes issues
|
||||
* with the mmc controllers making them unreliable
|
||||
*/
|
||||
grf = syscon_regmap_lookup_by_compatible("rockchip,rk3288-grf");
|
||||
if (!IS_ERR(grf))
|
||||
regmap_write(grf, RK3288_GRF_SOC_CON0, 0x10000000);
|
||||
else
|
||||
pr_err("rockchip: could not get grf syscon\n");
|
||||
}
|
||||
|
||||
of_clk_init(NULL);
|
||||
|
|
|
|||
|
|
@ -398,6 +398,9 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
|
|||
int pmp, unsigned long deadline,
|
||||
int (*check_ready)(struct ata_link *link));
|
||||
|
||||
int ahci_do_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline, bool *online);
|
||||
|
||||
unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
|
||||
int ahci_stop_engine(struct ata_port *ap);
|
||||
void ahci_start_fis_rx(struct ata_port *ap);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
#include <linux/ahci_platform.h>
|
||||
#include "ahci.h"
|
||||
|
||||
#define DRV_NAME "ahci_da850"
|
||||
#define DRV_NAME "ahci_da850"
|
||||
#define HARDRESET_RETRIES 5
|
||||
|
||||
/* SATA PHY Control Register offset from AHCI base */
|
||||
#define SATA_P0PHYCR_REG 0x178
|
||||
|
|
@ -28,17 +29,8 @@
|
|||
#define SATA_PHY_TXSWING(x) ((x) << 19)
|
||||
#define SATA_PHY_ENPLL(x) ((x) << 31)
|
||||
|
||||
/*
|
||||
* The multiplier needed for 1.5GHz PLL output.
|
||||
*
|
||||
* NOTE: This is currently hardcoded to be suitable for 100MHz crystal
|
||||
* frequency (which is used by DA850 EVM board) and may need to be changed
|
||||
* if you would like to use this driver on some other board.
|
||||
*/
|
||||
#define DA850_SATA_CLK_MULTIPLIER 7
|
||||
|
||||
static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
|
||||
void __iomem *ahci_base)
|
||||
void __iomem *ahci_base, u32 mpy)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
|
|
@ -47,18 +39,122 @@ static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
|
|||
val &= ~BIT(0);
|
||||
writel(val, pwrdn_reg);
|
||||
|
||||
val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) |
|
||||
SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) |
|
||||
SATA_PHY_ENPLL(1);
|
||||
val = SATA_PHY_MPY(mpy) | SATA_PHY_LOS(1) | SATA_PHY_RXCDR(4) |
|
||||
SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) | SATA_PHY_ENPLL(1);
|
||||
|
||||
writel(val, ahci_base + SATA_P0PHYCR_REG);
|
||||
}
|
||||
|
||||
static u32 ahci_da850_calculate_mpy(unsigned long refclk_rate)
|
||||
{
|
||||
u32 pll_output = 1500000000, needed;
|
||||
|
||||
/*
|
||||
* We need to determine the value of the multiplier (MPY) bits.
|
||||
* In order to include the 12.5 multiplier we need to first divide
|
||||
* the refclk rate by ten.
|
||||
*
|
||||
* __div64_32() turned out to be unreliable, sometimes returning
|
||||
* false results.
|
||||
*/
|
||||
WARN((refclk_rate % 10) != 0, "refclk must be divisible by 10");
|
||||
needed = pll_output / (refclk_rate / 10);
|
||||
|
||||
/*
|
||||
* What we have now is (multiplier * 10).
|
||||
*
|
||||
* Let's determine the actual register value we need to write.
|
||||
*/
|
||||
|
||||
switch (needed) {
|
||||
case 50:
|
||||
return 0x1;
|
||||
case 60:
|
||||
return 0x2;
|
||||
case 80:
|
||||
return 0x4;
|
||||
case 100:
|
||||
return 0x5;
|
||||
case 120:
|
||||
return 0x6;
|
||||
case 125:
|
||||
return 0x7;
|
||||
case 150:
|
||||
return 0x8;
|
||||
case 200:
|
||||
return 0x9;
|
||||
case 250:
|
||||
return 0xa;
|
||||
default:
|
||||
/*
|
||||
* We should have divided evenly - if not, return an invalid
|
||||
* value.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ahci_da850_softreset(struct ata_link *link,
|
||||
unsigned int *class, unsigned long deadline)
|
||||
{
|
||||
int pmp, ret;
|
||||
|
||||
pmp = sata_srst_pmp(link);
|
||||
|
||||
/*
|
||||
* There's an issue with the SATA controller on da850 SoCs: if we
|
||||
* enable Port Multiplier support, but the drive is connected directly
|
||||
* to the board, it can't be detected. As a workaround: if PMP is
|
||||
* enabled, we first call ahci_do_softreset() and pass it the result of
|
||||
* sata_srst_pmp(). If this call fails, we retry with pmp = 0.
|
||||
*/
|
||||
ret = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
|
||||
if (pmp && ret == -EBUSY)
|
||||
return ahci_do_softreset(link, class, 0,
|
||||
deadline, ahci_check_ready);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ahci_da850_hardreset(struct ata_link *link,
|
||||
unsigned int *class, unsigned long deadline)
|
||||
{
|
||||
int ret, retry = HARDRESET_RETRIES;
|
||||
bool online;
|
||||
|
||||
/*
|
||||
* In order to correctly service the LCD controller of the da850 SoC,
|
||||
* we increased the PLL0 frequency to 456MHz from the default 300MHz.
|
||||
*
|
||||
* This made the SATA controller unstable and the hardreset operation
|
||||
* does not always succeed the first time. Before really giving up to
|
||||
* bring up the link, retry the reset a couple times.
|
||||
*/
|
||||
do {
|
||||
ret = ahci_do_hardreset(link, class, deadline, &online);
|
||||
if (online)
|
||||
return ret;
|
||||
} while (retry--);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ata_port_operations ahci_da850_port_ops = {
|
||||
.inherits = &ahci_platform_ops,
|
||||
.softreset = ahci_da850_softreset,
|
||||
/*
|
||||
* No need to override .pmp_softreset - it's only used for actual
|
||||
* PMP-enabled ports.
|
||||
*/
|
||||
.hardreset = ahci_da850_hardreset,
|
||||
.pmp_hardreset = ahci_da850_hardreset,
|
||||
};
|
||||
|
||||
static const struct ata_port_info ahci_da850_port_info = {
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_platform_ops,
|
||||
.port_ops = &ahci_da850_port_ops,
|
||||
};
|
||||
|
||||
static struct scsi_host_template ahci_platform_sht = {
|
||||
|
|
@ -69,14 +165,52 @@ static int ahci_da850_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ahci_host_priv *hpriv;
|
||||
struct resource *res;
|
||||
void __iomem *pwrdn_reg;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
u32 mpy;
|
||||
int rc;
|
||||
|
||||
hpriv = ahci_platform_get_resources(pdev);
|
||||
if (IS_ERR(hpriv))
|
||||
return PTR_ERR(hpriv);
|
||||
|
||||
/*
|
||||
* Internally ahci_platform_get_resources() calls clk_get(dev, NULL)
|
||||
* when trying to obtain the functional clock. This SATA controller
|
||||
* uses two clocks for which we specify two connection ids. If we don't
|
||||
* have the functional clock at this point - call clk_get() again with
|
||||
* con_id = "fck".
|
||||
*/
|
||||
if (!hpriv->clks[0]) {
|
||||
clk = clk_get(dev, "fck");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
hpriv->clks[0] = clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* The second clock used by ahci-da850 is the external REFCLK. If we
|
||||
* didn't get it from ahci_platform_get_resources(), let's try to
|
||||
* specify the con_id in clk_get().
|
||||
*/
|
||||
if (!hpriv->clks[1]) {
|
||||
clk = clk_get(dev, "refclk");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "unable to obtain the reference clock");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hpriv->clks[1] = clk;
|
||||
}
|
||||
|
||||
mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
|
||||
if (mpy == 0) {
|
||||
dev_err(dev, "invalid REFCLK multiplier value: 0x%x", mpy);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = ahci_platform_enable_resources(hpriv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -89,7 +223,7 @@ static int ahci_da850_probe(struct platform_device *pdev)
|
|||
if (!pwrdn_reg)
|
||||
goto disable_resources;
|
||||
|
||||
da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
|
||||
da850_sata_init(dev, pwrdn_reg, hpriv->mmio, mpy);
|
||||
|
||||
rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
|
||||
&ahci_platform_sht);
|
||||
|
|
@ -105,11 +239,18 @@ disable_resources:
|
|||
static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
|
||||
ahci_platform_resume);
|
||||
|
||||
static const struct of_device_id ahci_da850_of_match[] = {
|
||||
{ .compatible = "ti,da850-ahci", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ahci_da850_of_match);
|
||||
|
||||
static struct platform_driver ahci_da850_driver = {
|
||||
.probe = ahci_da850_probe,
|
||||
.remove = ata_platform_remove_one,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = ahci_da850_of_match,
|
||||
.pm = &ahci_da850_pm_ops,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1519,8 +1519,8 @@ static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline)
|
||||
int ahci_do_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline, bool *online)
|
||||
{
|
||||
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
|
||||
struct ata_port *ap = link->ap;
|
||||
|
|
@ -1528,7 +1528,6 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
|
|||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
|
||||
struct ata_taskfile tf;
|
||||
bool online;
|
||||
int rc;
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
|
|
@ -1540,17 +1539,26 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
|
|||
tf.command = ATA_BUSY;
|
||||
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
|
||||
|
||||
rc = sata_link_hardreset(link, timing, deadline, &online,
|
||||
rc = sata_link_hardreset(link, timing, deadline, online,
|
||||
ahci_check_ready);
|
||||
|
||||
hpriv->start_engine(ap);
|
||||
|
||||
if (online)
|
||||
if (*online)
|
||||
*class = ahci_dev_classify(ap);
|
||||
|
||||
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ahci_do_hardreset);
|
||||
|
||||
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline)
|
||||
{
|
||||
bool online;
|
||||
|
||||
return ahci_do_hardreset(link, class, deadline, &online);
|
||||
}
|
||||
|
||||
static void ahci_postreset(struct ata_link *link, unsigned int *class)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ config QCOM_EBI2
|
|||
bool "Qualcomm External Bus Interface 2 (EBI2)"
|
||||
depends on HAS_IOMEM
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
default ARCH_QCOM
|
||||
help
|
||||
Say y here to enable support for the Qualcomm External Bus
|
||||
Interface 2, which can be used to connect things like NAND Flash,
|
||||
|
|
|
|||
|
|
@ -560,3 +560,21 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
|
|||
|
||||
return ret ? : le32_to_cpu(out);
|
||||
}
|
||||
|
||||
int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
|
||||
{
|
||||
struct {
|
||||
__le32 state;
|
||||
__le32 id;
|
||||
} req;
|
||||
__le32 scm_ret = 0;
|
||||
int ret;
|
||||
|
||||
req.state = cpu_to_le32(state);
|
||||
req.id = cpu_to_le32(id);
|
||||
|
||||
ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
|
||||
&req, sizeof(req), &scm_ret, sizeof(scm_ret));
|
||||
|
||||
return ret ? : le32_to_cpu(scm_ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -365,3 +365,19 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
|
|||
|
||||
return ret ? : res.a1;
|
||||
}
|
||||
|
||||
int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
|
||||
{
|
||||
struct qcom_scm_desc desc = {0};
|
||||
struct arm_smccc_res res;
|
||||
int ret;
|
||||
|
||||
desc.args[0] = state;
|
||||
desc.args[1] = id;
|
||||
desc.arginfo = QCOM_SCM_ARGS(2);
|
||||
|
||||
ret = qcom_scm_call(dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_SET_REMOTE_STATE,
|
||||
&desc, &res);
|
||||
|
||||
return ret ? : res.a1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,6 +324,12 @@ bool qcom_scm_is_available(void)
|
|||
}
|
||||
EXPORT_SYMBOL(qcom_scm_is_available);
|
||||
|
||||
int qcom_scm_set_remote_state(u32 state, u32 id)
|
||||
{
|
||||
return __qcom_scm_set_remote_state(__scm->dev, state, id);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_set_remote_state);
|
||||
|
||||
static int qcom_scm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_scm *scm;
|
||||
|
|
@ -387,7 +393,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|||
|
||||
static const struct of_device_id qcom_scm_dt_match[] = {
|
||||
{ .compatible = "qcom,scm-apq8064",
|
||||
.data = (void *) SCM_HAS_CORE_CLK,
|
||||
/* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */
|
||||
},
|
||||
{ .compatible = "qcom,scm-msm8660",
|
||||
.data = (void *) SCM_HAS_CORE_CLK,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#define QCOM_SCM_SVC_BOOT 0x1
|
||||
#define QCOM_SCM_BOOT_ADDR 0x1
|
||||
#define QCOM_SCM_BOOT_ADDR_MC 0x11
|
||||
#define QCOM_SCM_SET_REMOTE_STATE 0xa
|
||||
extern int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id);
|
||||
|
||||
#define QCOM_SCM_FLAG_HLOS 0x01
|
||||
#define QCOM_SCM_FLAG_COLDBOOT_MC 0x02
|
||||
|
|
|
|||
|
|
@ -76,9 +76,11 @@ struct at91_ebi_caps {
|
|||
|
||||
struct at91_ebi {
|
||||
struct clk *clk;
|
||||
struct regmap *smc;
|
||||
struct regmap *matrix;
|
||||
|
||||
struct {
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
} smc;
|
||||
struct regmap_field *ebi_csa;
|
||||
|
||||
struct device *dev;
|
||||
|
|
@ -93,7 +95,7 @@ static void at91sam9_ebi_get_config(struct at91_ebi_dev *ebid,
|
|||
struct at91_ebi_dev_config *conf)
|
||||
{
|
||||
struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
|
||||
unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
|
||||
unsigned int clk_period = NSEC_PER_SEC / clk_get_rate(ebid->ebi->clk);
|
||||
struct at91sam9_ebi_dev_config *config = &conf->sam9;
|
||||
struct at91sam9_smc_timings *timings = &config->timings;
|
||||
unsigned int val;
|
||||
|
|
@ -102,43 +104,43 @@ static void at91sam9_ebi_get_config(struct at91_ebi_dev *ebid,
|
|||
config->mode = val & ~AT91_SMC_TDF;
|
||||
|
||||
val = (val & AT91_SMC_TDF) >> 16;
|
||||
timings->tdf_ns = clk_rate * val;
|
||||
timings->tdf_ns = clk_period * val;
|
||||
|
||||
regmap_fields_read(fields->setup, conf->cs, &val);
|
||||
timings->ncs_rd_setup_ns = (val >> 24) & 0x1f;
|
||||
timings->ncs_rd_setup_ns += ((val >> 29) & 0x1) * 128;
|
||||
timings->ncs_rd_setup_ns *= clk_rate;
|
||||
timings->ncs_rd_setup_ns *= clk_period;
|
||||
timings->nrd_setup_ns = (val >> 16) & 0x1f;
|
||||
timings->nrd_setup_ns += ((val >> 21) & 0x1) * 128;
|
||||
timings->nrd_setup_ns *= clk_rate;
|
||||
timings->nrd_setup_ns *= clk_period;
|
||||
timings->ncs_wr_setup_ns = (val >> 8) & 0x1f;
|
||||
timings->ncs_wr_setup_ns += ((val >> 13) & 0x1) * 128;
|
||||
timings->ncs_wr_setup_ns *= clk_rate;
|
||||
timings->ncs_wr_setup_ns *= clk_period;
|
||||
timings->nwe_setup_ns = val & 0x1f;
|
||||
timings->nwe_setup_ns += ((val >> 5) & 0x1) * 128;
|
||||
timings->nwe_setup_ns *= clk_rate;
|
||||
timings->nwe_setup_ns *= clk_period;
|
||||
|
||||
regmap_fields_read(fields->pulse, conf->cs, &val);
|
||||
timings->ncs_rd_pulse_ns = (val >> 24) & 0x3f;
|
||||
timings->ncs_rd_pulse_ns += ((val >> 30) & 0x1) * 256;
|
||||
timings->ncs_rd_pulse_ns *= clk_rate;
|
||||
timings->ncs_rd_pulse_ns *= clk_period;
|
||||
timings->nrd_pulse_ns = (val >> 16) & 0x3f;
|
||||
timings->nrd_pulse_ns += ((val >> 22) & 0x1) * 256;
|
||||
timings->nrd_pulse_ns *= clk_rate;
|
||||
timings->nrd_pulse_ns *= clk_period;
|
||||
timings->ncs_wr_pulse_ns = (val >> 8) & 0x3f;
|
||||
timings->ncs_wr_pulse_ns += ((val >> 14) & 0x1) * 256;
|
||||
timings->ncs_wr_pulse_ns *= clk_rate;
|
||||
timings->ncs_wr_pulse_ns *= clk_period;
|
||||
timings->nwe_pulse_ns = val & 0x3f;
|
||||
timings->nwe_pulse_ns += ((val >> 6) & 0x1) * 256;
|
||||
timings->nwe_pulse_ns *= clk_rate;
|
||||
timings->nwe_pulse_ns *= clk_period;
|
||||
|
||||
regmap_fields_read(fields->cycle, conf->cs, &val);
|
||||
timings->nrd_cycle_ns = (val >> 16) & 0x7f;
|
||||
timings->nrd_cycle_ns += ((val >> 23) & 0x3) * 256;
|
||||
timings->nrd_cycle_ns *= clk_rate;
|
||||
timings->nrd_cycle_ns *= clk_period;
|
||||
timings->nwe_cycle_ns = val & 0x7f;
|
||||
timings->nwe_cycle_ns += ((val >> 7) & 0x3) * 256;
|
||||
timings->nwe_cycle_ns *= clk_rate;
|
||||
timings->nwe_cycle_ns *= clk_period;
|
||||
}
|
||||
|
||||
static int at91_xlate_timing(struct device_node *np, const char *prop,
|
||||
|
|
@ -334,6 +336,7 @@ static int at91sam9_ebi_apply_config(struct at91_ebi_dev *ebid,
|
|||
struct at91_ebi_dev_config *conf)
|
||||
{
|
||||
unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
|
||||
unsigned int clk_period = NSEC_PER_SEC / clk_rate;
|
||||
struct at91sam9_ebi_dev_config *config = &conf->sam9;
|
||||
struct at91sam9_smc_timings *timings = &config->timings;
|
||||
struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
|
||||
|
|
@ -376,7 +379,7 @@ static int at91sam9_ebi_apply_config(struct at91_ebi_dev *ebid,
|
|||
val |= AT91SAM9_SMC_NWECYCLE(coded_val);
|
||||
regmap_fields_write(fields->cycle, conf->cs, val);
|
||||
|
||||
val = DIV_ROUND_UP(timings->tdf_ns, clk_rate);
|
||||
val = DIV_ROUND_UP(timings->tdf_ns, clk_period);
|
||||
if (val > AT91_SMC_TDF_MAX)
|
||||
val = AT91_SMC_TDF_MAX;
|
||||
regmap_fields_write(fields->mode, conf->cs,
|
||||
|
|
@ -394,22 +397,26 @@ static int at91sam9_ebi_init(struct at91_ebi *ebi)
|
|||
field.id_offset = AT91SAM9_SMC_GENERIC_BLK_SZ;
|
||||
|
||||
field.reg = AT91SAM9_SMC_SETUP(AT91SAM9_SMC_GENERIC);
|
||||
fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
|
||||
field);
|
||||
if (IS_ERR(fields->setup))
|
||||
return PTR_ERR(fields->setup);
|
||||
|
||||
field.reg = AT91SAM9_SMC_PULSE(AT91SAM9_SMC_GENERIC);
|
||||
fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
|
||||
field);
|
||||
if (IS_ERR(fields->pulse))
|
||||
return PTR_ERR(fields->pulse);
|
||||
|
||||
field.reg = AT91SAM9_SMC_CYCLE(AT91SAM9_SMC_GENERIC);
|
||||
fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
|
||||
field);
|
||||
if (IS_ERR(fields->cycle))
|
||||
return PTR_ERR(fields->cycle);
|
||||
|
||||
field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC);
|
||||
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
|
||||
field);
|
||||
return PTR_ERR_OR_ZERO(fields->mode);
|
||||
}
|
||||
|
||||
|
|
@ -422,22 +429,26 @@ static int sama5d3_ebi_init(struct at91_ebi *ebi)
|
|||
field.id_offset = SAMA5_SMC_GENERIC_BLK_SZ;
|
||||
|
||||
field.reg = AT91SAM9_SMC_SETUP(SAMA5_SMC_GENERIC);
|
||||
fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
|
||||
field);
|
||||
if (IS_ERR(fields->setup))
|
||||
return PTR_ERR(fields->setup);
|
||||
|
||||
field.reg = AT91SAM9_SMC_PULSE(SAMA5_SMC_GENERIC);
|
||||
fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
|
||||
field);
|
||||
if (IS_ERR(fields->pulse))
|
||||
return PTR_ERR(fields->pulse);
|
||||
|
||||
field.reg = AT91SAM9_SMC_CYCLE(SAMA5_SMC_GENERIC);
|
||||
fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
|
||||
field);
|
||||
if (IS_ERR(fields->cycle))
|
||||
return PTR_ERR(fields->cycle);
|
||||
|
||||
field.reg = SAMA5_SMC_MODE(SAMA5_SMC_GENERIC);
|
||||
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc, field);
|
||||
fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
|
||||
field);
|
||||
return PTR_ERR_OR_ZERO(fields->mode);
|
||||
}
|
||||
|
||||
|
|
@ -448,12 +459,31 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
|
|||
struct at91_ebi_dev_config conf = { };
|
||||
struct device *dev = ebi->dev;
|
||||
struct at91_ebi_dev *ebid;
|
||||
int ret, numcs = 0, i;
|
||||
unsigned long cslines = 0;
|
||||
int ret, numcs = 0, nentries, i;
|
||||
bool apply = false;
|
||||
u32 cs;
|
||||
|
||||
numcs = of_property_count_elems_of_size(np, "reg",
|
||||
reg_cells * sizeof(u32));
|
||||
if (numcs <= 0) {
|
||||
nentries = of_property_count_elems_of_size(np, "reg",
|
||||
reg_cells * sizeof(u32));
|
||||
for (i = 0; i < nentries; i++) {
|
||||
ret = of_property_read_u32_index(np, "reg", i * reg_cells,
|
||||
&cs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cs >= AT91_MATRIX_EBI_NUM_CS ||
|
||||
!(ebi->caps->available_cs & BIT(cs))) {
|
||||
dev_err(dev, "invalid reg property in %s\n",
|
||||
np->full_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(cs, &cslines))
|
||||
numcs++;
|
||||
}
|
||||
|
||||
if (!numcs) {
|
||||
dev_err(dev, "invalid reg property in %s\n", np->full_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -472,21 +502,8 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
|
|||
else if (ret)
|
||||
apply = true;
|
||||
|
||||
for (i = 0; i < numcs; i++) {
|
||||
u32 cs;
|
||||
|
||||
ret = of_property_read_u32_index(np, "reg", i * reg_cells,
|
||||
&cs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cs > AT91_MATRIX_EBI_NUM_CS ||
|
||||
!(ebi->caps->available_cs & BIT(cs))) {
|
||||
dev_err(dev, "invalid reg property in %s\n",
|
||||
np->full_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for_each_set_bit(cs, &cslines, AT91_MATRIX_EBI_NUM_CS) {
|
||||
ebid->configs[i].cs = cs;
|
||||
|
||||
if (apply) {
|
||||
|
|
@ -502,9 +519,11 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
|
|||
* Attach the EBI device to the generic SMC logic if at least
|
||||
* one "atmel,smc-" property is present.
|
||||
*/
|
||||
if (ebi->ebi_csa && ret)
|
||||
if (ebi->ebi_csa && apply)
|
||||
regmap_field_update_bits(ebi->ebi_csa,
|
||||
BIT(cs), 0);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
list_add_tail(&ebid->node, &ebi->devs);
|
||||
|
|
@ -668,7 +687,7 @@ static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np)
|
|||
static int at91_ebi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *child, *np = dev->of_node;
|
||||
struct device_node *child, *np = dev->of_node, *smc_np;
|
||||
const struct of_device_id *match;
|
||||
struct at91_ebi *ebi;
|
||||
int ret, reg_cells;
|
||||
|
|
@ -693,9 +712,22 @@ static int at91_ebi_probe(struct platform_device *pdev)
|
|||
|
||||
ebi->clk = clk;
|
||||
|
||||
ebi->smc = syscon_regmap_lookup_by_phandle(np, "atmel,smc");
|
||||
if (IS_ERR(ebi->smc))
|
||||
return PTR_ERR(ebi->smc);
|
||||
smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0);
|
||||
|
||||
ebi->smc.regmap = syscon_node_to_regmap(smc_np);
|
||||
if (IS_ERR(ebi->smc.regmap))
|
||||
return PTR_ERR(ebi->smc.regmap);
|
||||
|
||||
ebi->smc.clk = of_clk_get(smc_np, 0);
|
||||
if (IS_ERR(ebi->smc.clk)) {
|
||||
if (PTR_ERR(ebi->smc.clk) != -ENOENT)
|
||||
return PTR_ERR(ebi->smc.clk);
|
||||
|
||||
ebi->smc.clk = NULL;
|
||||
}
|
||||
ret = clk_prepare_enable(ebi->smc.clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The sama5d3 does not provide an EBICSA register and thus does need
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue