mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 07:34:12 +08:00
ti-sysc interconnect target module driver changes for v5.3
This series of changes improves probing devices with ti-sysc to the point where we can now probe most devices without the custom dts property "ti,hwmods" and no legacy platform data :) We add support for platform data callbacks for idling and unidling the clockdomain the module belongs to. The rest of the series mostly adds handling for the various quirks needed by old legacy modules such as i2c and watchdog. Some quirk handling is still missing for few modules, but those will be added as they get tested. The related platform data and dts changes will be sent separately. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEkgNvrZJU/QSQYIcQG9Q+yVyrpXMFAl0AuTURHHRvbnlAYXRv bWlkZS5jb20ACgkQG9Q+yVyrpXPn4A//Z7uWk98dwcIs8/28CaFTPsRGhx3p+hj0 Mafl3eT5Q/y0TFGkMw3g5LSX5EZlz+5t6eFsolU+O8p6jsPoo5mcsGQfgkraydE3 x0wfSkFiqJcTP4FFvrwcekSQZGjpeZoUdQZ/e2epSDWvPx9gRzLFR3wCLPJ1MOgg dveEJTnPfpFLliTZeVpcn4v2P4+KfBn4iu2ojr9qcLZL9QNFZr3NQLRdx6kUw7qf b3eRugzx3sBA4pKLEfqrOzqjP77W9sy1zDN5rA3GNgo+b+OyBhdu/pxxkREP4t4+ 8/1E/JndDVkO98ooFJ+MWdnh8HQmefEjyaoaYa7LN6438mivkOFPFAUMtuOdKzv/ FTa9r7xpo1Iq5b3HyE7NA+xZfoHKBEHzY0zbNyJLz75Ctnh3zOuHAA3xwxOlbgn+ UX/1DAS/7ALUXrXkk331VVzYX5UfOxrH2+CF2GF9vpCNZZ17Qp3ZKy4XW1Qv9nfy nozOkqSvbGG0tzhq+wLd6Soo2Vns7CfHRqDB8txLeBGtrk/kahHsxe7dLo4+fHk6 DH0R7mZ6QnvaMWpJwkqoBUp7lD9ej9/pw2newbb5RyUDQqMjNvdY3zcBOeXeWulh m2hWFKt1JTGTvXtbTjOOnfQIyICUClMzo4VowLBplfZELJvK781/5P3Jb4ZOFF0N I1DN4vDxqMg= =Fxul -----END PGP SIGNATURE----- Merge tag 'omap-for-v5.3/ti-sysc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into arm/drivers ti-sysc interconnect target module driver changes for v5.3 This series of changes improves probing devices with ti-sysc to the point where we can now probe most devices without the custom dts property "ti,hwmods" and no legacy platform data :) We add support for platform data callbacks for idling and unidling the clockdomain the module belongs to. The rest of the series mostly adds handling for the various quirks needed by old legacy modules such as i2c and watchdog. Some quirk handling is still missing for few modules, but those will be added as they get tested. The related platform data and dts changes will be sent separately. * tag 'omap-for-v5.3/ti-sysc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: bus: ti-sysc: Add support for module specific reset quirks bus: ti-sysc: Detect uarts also on omap34xx bus: ti-sysc: Do rstctrl reset handling in two phases bus: ti-sysc: Add support for disabling module without legacy mode bus: ti-sysc: Set ENAWAKEUP if available bus: ti-sysc: Handle swsup idle mode quirks bus: ti-sysc: Handle clockactivity for enable and disable bus: ti-sysc: Enable interconnect target module autoidle bit on enable bus: ti-sysc: Allow QUIRK_LEGACY_IDLE even if legacy_mode is not set bus: ti-sysc: Make OCP reset work for sysstatus and sysconfig reset bits bus: ti-sysc: Support 16-bit writes too bus: ti-sysc: Add support for missing clockdomain handling ARM: dts: dra71x: Disable usb4_tm target module ARM: dts: dra71x: Disable rtc target module ARM: dts: dra76x: Disable usb4_tm target module ARM: dts: dra76x: Disable rtc target module ARM: dts: dra76x: Update MMC2_HS200_MANUAL1 iodelay values ARM: dts: am57xx-idk: Remove support for voltage switching for SD card bus: ti-sysc: Handle devices with no control registers ARM: dts: Configure osc clock for d_can on am335x Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
c3bd15a078
@ -1759,11 +1759,10 @@
|
||||
target-module@cc000 { /* 0x481cc000, ap 60 46.0 */
|
||||
compatible = "ti,sysc-omap4", "ti,sysc";
|
||||
ti,hwmods = "d_can0";
|
||||
reg = <0xcc000 0x4>;
|
||||
reg-names = "rev";
|
||||
/* Domains (P, C): per_pwrdm, l4ls_clkdm */
|
||||
clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN0_CLKCTRL 0>;
|
||||
clock-names = "fck";
|
||||
clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN0_CLKCTRL 0>,
|
||||
<&dcan0_fck>;
|
||||
clock-names = "fck", "osc";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x0 0xcc000 0x2000>;
|
||||
@ -1782,11 +1781,10 @@
|
||||
target-module@d0000 { /* 0x481d0000, ap 62 42.0 */
|
||||
compatible = "ti,sysc-omap4", "ti,sysc";
|
||||
ti,hwmods = "d_can1";
|
||||
reg = <0xd0000 0x4>;
|
||||
reg-names = "rev";
|
||||
/* Domains (P, C): per_pwrdm, l4ls_clkdm */
|
||||
clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN1_CLKCTRL 0>;
|
||||
clock-names = "fck";
|
||||
clocks = <&l4ls_clkctrl AM3_L4LS_D_CAN1_CLKCTRL 0>,
|
||||
<&dcan1_fck>;
|
||||
clock-names = "fck", "osc";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x0 0xd0000 0x2000>;
|
||||
|
@ -1575,8 +1575,6 @@
|
||||
target-module@cc000 { /* 0x481cc000, ap 50 46.0 */
|
||||
compatible = "ti,sysc-omap4", "ti,sysc";
|
||||
ti,hwmods = "d_can0";
|
||||
reg = <0xcc000 0x4>;
|
||||
reg-names = "rev";
|
||||
/* Domains (P, C): per_pwrdm, l4ls_clkdm */
|
||||
clocks = <&l4ls_clkctrl AM4_L4LS_D_CAN0_CLKCTRL 0>;
|
||||
clock-names = "fck";
|
||||
@ -1596,8 +1594,6 @@
|
||||
target-module@d0000 { /* 0x481d0000, ap 52 3a.0 */
|
||||
compatible = "ti,sysc-omap4", "ti,sysc";
|
||||
ti,hwmods = "d_can1";
|
||||
reg = <0xd0000 0x4>;
|
||||
reg-names = "rev";
|
||||
/* Domains (P, C): per_pwrdm, l4ls_clkdm */
|
||||
clocks = <&l4ls_clkctrl AM4_L4LS_D_CAN1_CLKCTRL 0>;
|
||||
clock-names = "fck";
|
||||
|
@ -420,6 +420,7 @@
|
||||
vqmmc-supply = <&ldo1_reg>;
|
||||
bus-width = <4>;
|
||||
cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>; /* gpio 219 */
|
||||
no-1-8-v;
|
||||
};
|
||||
|
||||
&mmc2 {
|
||||
|
@ -3543,7 +3543,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
target-module@38000 { /* 0x48838000, ap 29 12.0 */
|
||||
rtctarget: target-module@38000 { /* 0x48838000, ap 29 12.0 */
|
||||
compatible = "ti,sysc-omap4-simple", "ti,sysc";
|
||||
ti,hwmods = "rtcss";
|
||||
reg = <0x38074 0x4>,
|
||||
|
@ -6,7 +6,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "dra72-evm-common.dtsi"
|
||||
#include "dra71x.dtsi"
|
||||
#include "dra7-mmc-iodelay.dtsi"
|
||||
#include "dra72x-mmc-iodelay.dtsi"
|
||||
#include <dt-bindings/net/ti-dp83867.h>
|
||||
|
17
arch/arm/boot/dts/dra71x.dtsi
Normal file
17
arch/arm/boot/dts/dra71x.dtsi
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "dra72-evm-common.dtsi"
|
||||
|
||||
&rtctarget {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&usb4_tm {
|
||||
status = "disabled";
|
||||
};
|
@ -22,7 +22,7 @@
|
||||
*
|
||||
* Datamanual Revisions:
|
||||
*
|
||||
* DRA76x Silicon Revision 1.0: SPRS993A, Revised July 2017
|
||||
* DRA76x Silicon Revision 1.0: SPRS993E, Revised December 2018
|
||||
*
|
||||
*/
|
||||
|
||||
@ -169,25 +169,25 @@
|
||||
/* Corresponds to MMC2_HS200_MANUAL1 in datamanual */
|
||||
mmc2_iodelay_hs200_conf: mmc2_iodelay_hs200_conf {
|
||||
pinctrl-pin-array = <
|
||||
0x190 A_DELAY_PS(384) G_DELAY_PS(0) /* CFG_GPMC_A19_OEN */
|
||||
0x194 A_DELAY_PS(0) G_DELAY_PS(174) /* CFG_GPMC_A19_OUT */
|
||||
0x1a8 A_DELAY_PS(410) G_DELAY_PS(0) /* CFG_GPMC_A20_OEN */
|
||||
0x1ac A_DELAY_PS(85) G_DELAY_PS(0) /* CFG_GPMC_A20_OUT */
|
||||
0x1b4 A_DELAY_PS(468) G_DELAY_PS(0) /* CFG_GPMC_A21_OEN */
|
||||
0x1b8 A_DELAY_PS(139) G_DELAY_PS(0) /* CFG_GPMC_A21_OUT */
|
||||
0x1c0 A_DELAY_PS(676) G_DELAY_PS(0) /* CFG_GPMC_A22_OEN */
|
||||
0x1c4 A_DELAY_PS(69) G_DELAY_PS(0) /* CFG_GPMC_A22_OUT */
|
||||
0x1d0 A_DELAY_PS(1062) G_DELAY_PS(154) /* CFG_GPMC_A23_OUT */
|
||||
0x1d8 A_DELAY_PS(640) G_DELAY_PS(0) /* CFG_GPMC_A24_OEN */
|
||||
0x1dc A_DELAY_PS(0) G_DELAY_PS(0) /* CFG_GPMC_A24_OUT */
|
||||
0x1e4 A_DELAY_PS(356) G_DELAY_PS(0) /* CFG_GPMC_A25_OEN */
|
||||
0x1e8 A_DELAY_PS(0) G_DELAY_PS(0) /* CFG_GPMC_A25_OUT */
|
||||
0x1f0 A_DELAY_PS(579) G_DELAY_PS(0) /* CFG_GPMC_A26_OEN */
|
||||
0x1f4 A_DELAY_PS(0) G_DELAY_PS(0) /* CFG_GPMC_A26_OUT */
|
||||
0x1fc A_DELAY_PS(435) G_DELAY_PS(0) /* CFG_GPMC_A27_OEN */
|
||||
0x200 A_DELAY_PS(36) G_DELAY_PS(0) /* CFG_GPMC_A27_OUT */
|
||||
0x364 A_DELAY_PS(759) G_DELAY_PS(0) /* CFG_GPMC_CS1_OEN */
|
||||
0x368 A_DELAY_PS(72) G_DELAY_PS(0) /* CFG_GPMC_CS1_OUT */
|
||||
0x190 A_DELAY_PS(384) G_DELAY_PS(0) /* CFG_GPMC_A19_OEN */
|
||||
0x194 A_DELAY_PS(350) G_DELAY_PS(174) /* CFG_GPMC_A19_OUT */
|
||||
0x1a8 A_DELAY_PS(410) G_DELAY_PS(0) /* CFG_GPMC_A20_OEN */
|
||||
0x1ac A_DELAY_PS(335) G_DELAY_PS(0) /* CFG_GPMC_A20_OUT */
|
||||
0x1b4 A_DELAY_PS(468) G_DELAY_PS(0) /* CFG_GPMC_A21_OEN */
|
||||
0x1b8 A_DELAY_PS(339) G_DELAY_PS(0) /* CFG_GPMC_A21_OUT */
|
||||
0x1c0 A_DELAY_PS(676) G_DELAY_PS(0) /* CFG_GPMC_A22_OEN */
|
||||
0x1c4 A_DELAY_PS(219) G_DELAY_PS(0) /* CFG_GPMC_A22_OUT */
|
||||
0x1d0 A_DELAY_PS(1062) G_DELAY_PS(154) /* CFG_GPMC_A23_OUT */
|
||||
0x1d8 A_DELAY_PS(640) G_DELAY_PS(0) /* CFG_GPMC_A24_OEN */
|
||||
0x1dc A_DELAY_PS(150) G_DELAY_PS(0) /* CFG_GPMC_A24_OUT */
|
||||
0x1e4 A_DELAY_PS(356) G_DELAY_PS(0) /* CFG_GPMC_A25_OEN */
|
||||
0x1e8 A_DELAY_PS(150) G_DELAY_PS(0) /* CFG_GPMC_A25_OUT */
|
||||
0x1f0 A_DELAY_PS(579) G_DELAY_PS(0) /* CFG_GPMC_A26_OEN */
|
||||
0x1f4 A_DELAY_PS(200) G_DELAY_PS(0) /* CFG_GPMC_A26_OUT */
|
||||
0x1fc A_DELAY_PS(435) G_DELAY_PS(0) /* CFG_GPMC_A27_OEN */
|
||||
0x200 A_DELAY_PS(236) G_DELAY_PS(0) /* CFG_GPMC_A27_OUT */
|
||||
0x364 A_DELAY_PS(759) G_DELAY_PS(0) /* CFG_GPMC_CS1_OEN */
|
||||
0x368 A_DELAY_PS(372) G_DELAY_PS(0) /* CFG_GPMC_CS1_OUT */
|
||||
>;
|
||||
};
|
||||
|
||||
|
@ -81,3 +81,11 @@
|
||||
reg = <0x3fc>;
|
||||
};
|
||||
};
|
||||
|
||||
&rtctarget {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&usb4_tm {
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -3445,6 +3445,7 @@ static int omap_hwmod_check_module(struct device *dev,
|
||||
* @dev: struct device
|
||||
* @oh: module
|
||||
* @sysc_fields: sysc register bits
|
||||
* @clockdomain: clockdomain
|
||||
* @rev_offs: revision register offset
|
||||
* @sysc_offs: sysconfig register offset
|
||||
* @syss_offs: sysstatus register offset
|
||||
@ -3456,6 +3457,7 @@ static int omap_hwmod_check_module(struct device *dev,
|
||||
static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
|
||||
const struct ti_sysc_module_data *data,
|
||||
struct sysc_regbits *sysc_fields,
|
||||
struct clockdomain *clkdm,
|
||||
s32 rev_offs, s32 sysc_offs,
|
||||
s32 syss_offs, u32 sysc_flags,
|
||||
u32 idlemodes)
|
||||
@ -3463,8 +3465,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
|
||||
struct omap_hwmod_class_sysconfig *sysc;
|
||||
struct omap_hwmod_class *class = NULL;
|
||||
struct omap_hwmod_ocp_if *oi = NULL;
|
||||
struct clockdomain *clkdm = NULL;
|
||||
struct clk *clk = NULL;
|
||||
void __iomem *regs = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
@ -3511,36 +3511,6 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
|
||||
oi->user = OCP_USER_MPU | OCP_USER_SDMA;
|
||||
}
|
||||
|
||||
if (!oh->_clk) {
|
||||
struct clk_hw_omap *hwclk;
|
||||
|
||||
clk = of_clk_get_by_name(dev->of_node, "fck");
|
||||
if (!IS_ERR(clk))
|
||||
clk_prepare(clk);
|
||||
else
|
||||
clk = NULL;
|
||||
|
||||
/*
|
||||
* Populate clockdomain based on dts clock. It is needed for
|
||||
* clkdm_deny_idle() and clkdm_allow_idle() until we have have
|
||||
* interconnect driver and reset driver capable of blocking
|
||||
* clockdomain idle during reset, enable and idle.
|
||||
*/
|
||||
if (clk) {
|
||||
hwclk = to_clk_hw_omap(__clk_get_hw(clk));
|
||||
if (hwclk && hwclk->clkdm_name)
|
||||
clkdm = clkdm_lookup(hwclk->clkdm_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that we assume interconnect driver manages the clocks
|
||||
* and do not need to populate oh->_clk for dynamically
|
||||
* allocated modules.
|
||||
*/
|
||||
clk_unprepare(clk);
|
||||
clk_put(clk);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&oh->_lock, flags);
|
||||
if (regs)
|
||||
oh->_mpu_rt_va = regs;
|
||||
@ -3626,7 +3596,7 @@ int omap_hwmod_init_module(struct device *dev,
|
||||
u32 sysc_flags, idlemodes;
|
||||
int error;
|
||||
|
||||
if (!dev || !data)
|
||||
if (!dev || !data || !data->name || !cookie)
|
||||
return -EINVAL;
|
||||
|
||||
oh = _lookup(data->name);
|
||||
@ -3697,7 +3667,8 @@ int omap_hwmod_init_module(struct device *dev,
|
||||
return error;
|
||||
|
||||
return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
|
||||
rev_offs, sysc_offs, syss_offs,
|
||||
cookie->clkdm, rev_offs,
|
||||
sysc_offs, syss_offs,
|
||||
sysc_flags, idlemodes);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/platform_data/wkup_m3.h>
|
||||
#include <linux/platform_data/asoc-ti-mcbsp.h>
|
||||
|
||||
#include "clockdomain.h"
|
||||
#include "common.h"
|
||||
#include "common-board-devices.h"
|
||||
#include "control.h"
|
||||
@ -463,6 +464,62 @@ static void __init dra7x_evm_mmc_quirk(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct clockdomain *ti_sysc_find_one_clockdomain(struct clk *clk)
|
||||
{
|
||||
struct clockdomain *clkdm = NULL;
|
||||
struct clk_hw_omap *hwclk;
|
||||
|
||||
hwclk = to_clk_hw_omap(__clk_get_hw(clk));
|
||||
if (hwclk && hwclk->clkdm_name)
|
||||
clkdm = clkdm_lookup(hwclk->clkdm_name);
|
||||
|
||||
return clkdm;
|
||||
}
|
||||
|
||||
/**
|
||||
* ti_sysc_clkdm_init - find clockdomain based on clock
|
||||
* @fck: device functional clock
|
||||
* @ick: device interface clock
|
||||
* @dev: struct device
|
||||
*
|
||||
* Populate clockdomain based on clock. It is needed for
|
||||
* clkdm_deny_idle() and clkdm_allow_idle() for blocking clockdomain
|
||||
* clockdomain idle during reset, enable and idle.
|
||||
*
|
||||
* Note that we assume interconnect driver manages the clocks
|
||||
* and do not need to populate oh->_clk for dynamically
|
||||
* allocated modules.
|
||||
*/
|
||||
static int ti_sysc_clkdm_init(struct device *dev,
|
||||
struct clk *fck, struct clk *ick,
|
||||
struct ti_sysc_cookie *cookie)
|
||||
{
|
||||
if (fck)
|
||||
cookie->clkdm = ti_sysc_find_one_clockdomain(fck);
|
||||
if (cookie->clkdm)
|
||||
return 0;
|
||||
if (ick)
|
||||
cookie->clkdm = ti_sysc_find_one_clockdomain(ick);
|
||||
if (cookie->clkdm)
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void ti_sysc_clkdm_deny_idle(struct device *dev,
|
||||
const struct ti_sysc_cookie *cookie)
|
||||
{
|
||||
if (cookie->clkdm)
|
||||
clkdm_deny_idle(cookie->clkdm);
|
||||
}
|
||||
|
||||
static void ti_sysc_clkdm_allow_idle(struct device *dev,
|
||||
const struct ti_sysc_cookie *cookie)
|
||||
{
|
||||
if (cookie->clkdm)
|
||||
clkdm_allow_idle(cookie->clkdm);
|
||||
}
|
||||
|
||||
static int ti_sysc_enable_module(struct device *dev,
|
||||
const struct ti_sysc_cookie *cookie)
|
||||
{
|
||||
@ -494,6 +551,9 @@ static struct of_dev_auxdata omap_auxdata_lookup[];
|
||||
|
||||
static struct ti_sysc_platform_data ti_sysc_pdata = {
|
||||
.auxdata = omap_auxdata_lookup,
|
||||
.init_clockdomain = ti_sysc_clkdm_init,
|
||||
.clkdm_deny_idle = ti_sysc_clkdm_deny_idle,
|
||||
.clkdm_allow_idle = ti_sysc_clkdm_allow_idle,
|
||||
.init_module = omap_hwmod_init_module,
|
||||
.enable_module = ti_sysc_enable_module,
|
||||
.idle_module = ti_sysc_idle_module,
|
||||
|
@ -71,6 +71,9 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = {
|
||||
* @name: name if available
|
||||
* @revision: interconnect target module revision
|
||||
* @needs_resume: runtime resume needed on resume from suspend
|
||||
* @clk_enable_quirk: module specific clock enable quirk
|
||||
* @clk_disable_quirk: module specific clock disable quirk
|
||||
* @reset_done_quirk: module specific reset done quirk
|
||||
*/
|
||||
struct sysc {
|
||||
struct device *dev;
|
||||
@ -89,10 +92,14 @@ struct sysc {
|
||||
struct ti_sysc_cookie cookie;
|
||||
const char *name;
|
||||
u32 revision;
|
||||
bool enabled;
|
||||
bool needs_resume;
|
||||
bool child_needs_resume;
|
||||
unsigned int enabled:1;
|
||||
unsigned int needs_resume:1;
|
||||
unsigned int child_needs_resume:1;
|
||||
unsigned int disable_on_idle:1;
|
||||
struct delayed_work idle_work;
|
||||
void (*clk_enable_quirk)(struct sysc *sysc);
|
||||
void (*clk_disable_quirk)(struct sysc *sysc);
|
||||
void (*reset_done_quirk)(struct sysc *sysc);
|
||||
};
|
||||
|
||||
static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
|
||||
@ -100,6 +107,20 @@ static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
|
||||
|
||||
static void sysc_write(struct sysc *ddata, int offset, u32 value)
|
||||
{
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
|
||||
writew_relaxed(value & 0xffff, ddata->module_va + offset);
|
||||
|
||||
/* Only i2c revision has LO and HI register with stride of 4 */
|
||||
if (ddata->offsets[SYSC_REVISION] >= 0 &&
|
||||
offset == ddata->offsets[SYSC_REVISION]) {
|
||||
u16 hi = value >> 16;
|
||||
|
||||
writew_relaxed(hi, ddata->module_va + offset + 4);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
writel_relaxed(value, ddata->module_va + offset);
|
||||
}
|
||||
|
||||
@ -109,7 +130,14 @@ static u32 sysc_read(struct sysc *ddata, int offset)
|
||||
u32 val;
|
||||
|
||||
val = readw_relaxed(ddata->module_va + offset);
|
||||
val |= (readw_relaxed(ddata->module_va + offset + 4) << 16);
|
||||
|
||||
/* Only i2c revision has LO and HI register with stride of 4 */
|
||||
if (ddata->offsets[SYSC_REVISION] >= 0 &&
|
||||
offset == ddata->offsets[SYSC_REVISION]) {
|
||||
u16 tmp = readw_relaxed(ddata->module_va + offset + 4);
|
||||
|
||||
val |= tmp << 16;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
@ -132,6 +160,26 @@ static u32 sysc_read_revision(struct sysc *ddata)
|
||||
return sysc_read(ddata, offset);
|
||||
}
|
||||
|
||||
static u32 sysc_read_sysconfig(struct sysc *ddata)
|
||||
{
|
||||
int offset = ddata->offsets[SYSC_SYSCONFIG];
|
||||
|
||||
if (offset < 0)
|
||||
return 0;
|
||||
|
||||
return sysc_read(ddata, offset);
|
||||
}
|
||||
|
||||
static u32 sysc_read_sysstatus(struct sysc *ddata)
|
||||
{
|
||||
int offset = ddata->offsets[SYSC_SYSSTATUS];
|
||||
|
||||
if (offset < 0)
|
||||
return 0;
|
||||
|
||||
return sysc_read(ddata, offset);
|
||||
}
|
||||
|
||||
static int sysc_add_named_clock_from_child(struct sysc *ddata,
|
||||
const char *name,
|
||||
const char *optfck_name)
|
||||
@ -422,6 +470,30 @@ static void sysc_disable_opt_clocks(struct sysc *ddata)
|
||||
}
|
||||
}
|
||||
|
||||
static void sysc_clkdm_deny_idle(struct sysc *ddata)
|
||||
{
|
||||
struct ti_sysc_platform_data *pdata;
|
||||
|
||||
if (ddata->legacy_mode)
|
||||
return;
|
||||
|
||||
pdata = dev_get_platdata(ddata->dev);
|
||||
if (pdata && pdata->clkdm_deny_idle)
|
||||
pdata->clkdm_deny_idle(ddata->dev, &ddata->cookie);
|
||||
}
|
||||
|
||||
static void sysc_clkdm_allow_idle(struct sysc *ddata)
|
||||
{
|
||||
struct ti_sysc_platform_data *pdata;
|
||||
|
||||
if (ddata->legacy_mode)
|
||||
return;
|
||||
|
||||
pdata = dev_get_platdata(ddata->dev);
|
||||
if (pdata && pdata->clkdm_allow_idle)
|
||||
pdata->clkdm_allow_idle(ddata->dev, &ddata->cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysc_init_resets - init rstctrl reset line if configured
|
||||
* @ddata: device driver data
|
||||
@ -431,7 +503,7 @@ static void sysc_disable_opt_clocks(struct sysc *ddata)
|
||||
static int sysc_init_resets(struct sysc *ddata)
|
||||
{
|
||||
ddata->rsts =
|
||||
devm_reset_control_array_get_optional_exclusive(ddata->dev);
|
||||
devm_reset_control_get_optional(ddata->dev, "rstctrl");
|
||||
if (IS_ERR(ddata->rsts))
|
||||
return PTR_ERR(ddata->rsts);
|
||||
|
||||
@ -660,12 +732,6 @@ static int sysc_check_registers(struct sysc *ddata)
|
||||
nr_regs++;
|
||||
}
|
||||
|
||||
if (nr_regs < 1) {
|
||||
dev_err(ddata->dev, "missing registers\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nr_matches > nr_regs) {
|
||||
dev_err(ddata->dev, "overlapping registers: (%i/%i)",
|
||||
nr_regs, nr_matches);
|
||||
@ -691,12 +757,21 @@ static int sysc_ioremap(struct sysc *ddata)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = max3(ddata->offsets[SYSC_REVISION],
|
||||
ddata->offsets[SYSC_SYSCONFIG],
|
||||
ddata->offsets[SYSC_SYSSTATUS]);
|
||||
if (ddata->offsets[SYSC_REVISION] < 0 &&
|
||||
ddata->offsets[SYSC_SYSCONFIG] < 0 &&
|
||||
ddata->offsets[SYSC_SYSSTATUS] < 0) {
|
||||
size = ddata->module_size;
|
||||
} else {
|
||||
size = max3(ddata->offsets[SYSC_REVISION],
|
||||
ddata->offsets[SYSC_SYSCONFIG],
|
||||
ddata->offsets[SYSC_SYSSTATUS]);
|
||||
|
||||
if (size < 0 || (size + sizeof(u32)) > ddata->module_size)
|
||||
return -EINVAL;
|
||||
if (size < SZ_1K)
|
||||
size = SZ_1K;
|
||||
|
||||
if ((size + sizeof(u32)) > ddata->module_size)
|
||||
size = ddata->module_size;
|
||||
}
|
||||
|
||||
ddata->module_va = devm_ioremap(ddata->dev,
|
||||
ddata->module_pa,
|
||||
@ -794,7 +869,9 @@ static void sysc_show_registers(struct sysc *ddata)
|
||||
}
|
||||
|
||||
#define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1)
|
||||
#define SYSC_CLOCACT_ICK 2
|
||||
|
||||
/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */
|
||||
static int sysc_enable_module(struct device *dev)
|
||||
{
|
||||
struct sysc *ddata;
|
||||
@ -805,23 +882,34 @@ static int sysc_enable_module(struct device *dev)
|
||||
if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* TODO: Need to prevent clockdomain autoidle?
|
||||
* See clkdm_deny_idle() in arch/mach-omap2/omap_hwmod.c
|
||||
*/
|
||||
|
||||
regbits = ddata->cap->regbits;
|
||||
reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||
|
||||
/* Set CLOCKACTIVITY, we only use it for ick */
|
||||
if (regbits->clkact_shift >= 0 &&
|
||||
(ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT ||
|
||||
ddata->cfg.sysc_val & BIT(regbits->clkact_shift)))
|
||||
reg |= SYSC_CLOCACT_ICK << regbits->clkact_shift;
|
||||
|
||||
/* Set SIDLE mode */
|
||||
idlemodes = ddata->cfg.sidlemodes;
|
||||
if (!idlemodes || regbits->sidle_shift < 0)
|
||||
goto set_midle;
|
||||
|
||||
best_mode = fls(ddata->cfg.sidlemodes) - 1;
|
||||
if (best_mode > SYSC_IDLE_MASK) {
|
||||
dev_err(dev, "%s: invalid sidlemode\n", __func__);
|
||||
return -EINVAL;
|
||||
if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_SIDLE |
|
||||
SYSC_QUIRK_SWSUP_SIDLE_ACT)) {
|
||||
best_mode = SYSC_IDLE_NO;
|
||||
} else {
|
||||
best_mode = fls(ddata->cfg.sidlemodes) - 1;
|
||||
if (best_mode > SYSC_IDLE_MASK) {
|
||||
dev_err(dev, "%s: invalid sidlemode\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set WAKEUP */
|
||||
if (regbits->enwkup_shift >= 0 &&
|
||||
ddata->cfg.sysc_val & BIT(regbits->enwkup_shift))
|
||||
reg |= BIT(regbits->enwkup_shift);
|
||||
}
|
||||
|
||||
reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
|
||||
@ -832,7 +920,7 @@ set_midle:
|
||||
/* Set MIDLE mode */
|
||||
idlemodes = ddata->cfg.midlemodes;
|
||||
if (!idlemodes || regbits->midle_shift < 0)
|
||||
return 0;
|
||||
goto set_autoidle;
|
||||
|
||||
best_mode = fls(ddata->cfg.midlemodes) - 1;
|
||||
if (best_mode > SYSC_IDLE_MASK) {
|
||||
@ -844,6 +932,14 @@ set_midle:
|
||||
reg |= best_mode << regbits->midle_shift;
|
||||
sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
|
||||
|
||||
set_autoidle:
|
||||
/* Autoidle bit must enabled separately if available */
|
||||
if (regbits->autoidle_shift >= 0 &&
|
||||
ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) {
|
||||
reg |= 1 << regbits->autoidle_shift;
|
||||
sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -861,6 +957,7 @@ static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */
|
||||
static int sysc_disable_module(struct device *dev)
|
||||
{
|
||||
struct sysc *ddata;
|
||||
@ -872,11 +969,6 @@ static int sysc_disable_module(struct device *dev)
|
||||
if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* TODO: Need to prevent clockdomain autoidle?
|
||||
* See clkdm_deny_idle() in arch/mach-omap2/omap_hwmod.c
|
||||
*/
|
||||
|
||||
regbits = ddata->cap->regbits;
|
||||
reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
|
||||
|
||||
@ -901,14 +993,21 @@ set_sidle:
|
||||
if (!idlemodes || regbits->sidle_shift < 0)
|
||||
return 0;
|
||||
|
||||
ret = sysc_best_idle_mode(idlemodes, &best_mode);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: invalid sidlemode\n", __func__);
|
||||
return ret;
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE) {
|
||||
best_mode = SYSC_IDLE_FORCE;
|
||||
} else {
|
||||
ret = sysc_best_idle_mode(idlemodes, &best_mode);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: invalid sidlemode\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
|
||||
reg |= best_mode << regbits->sidle_shift;
|
||||
if (regbits->autoidle_shift >= 0 &&
|
||||
ddata->cfg.sysc_val & BIT(regbits->autoidle_shift))
|
||||
reg |= 1 << regbits->autoidle_shift;
|
||||
sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
|
||||
|
||||
return 0;
|
||||
@ -932,6 +1031,9 @@ static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev,
|
||||
dev_err(dev, "%s: could not idle: %i\n",
|
||||
__func__, error);
|
||||
|
||||
if (ddata->disable_on_idle)
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -941,6 +1043,9 @@ static int __maybe_unused sysc_runtime_resume_legacy(struct device *dev,
|
||||
struct ti_sysc_platform_data *pdata;
|
||||
int error;
|
||||
|
||||
if (ddata->disable_on_idle)
|
||||
reset_control_deassert(ddata->rsts);
|
||||
|
||||
pdata = dev_get_platdata(ddata->dev);
|
||||
if (!pdata)
|
||||
return 0;
|
||||
@ -966,14 +1071,16 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev)
|
||||
if (!ddata->enabled)
|
||||
return 0;
|
||||
|
||||
sysc_clkdm_deny_idle(ddata);
|
||||
|
||||
if (ddata->legacy_mode) {
|
||||
error = sysc_runtime_suspend_legacy(dev, ddata);
|
||||
if (error)
|
||||
return error;
|
||||
goto err_allow_idle;
|
||||
} else {
|
||||
error = sysc_disable_module(dev);
|
||||
if (error)
|
||||
return error;
|
||||
goto err_allow_idle;
|
||||
}
|
||||
|
||||
sysc_disable_main_clocks(ddata);
|
||||
@ -983,6 +1090,12 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev)
|
||||
|
||||
ddata->enabled = false;
|
||||
|
||||
err_allow_idle:
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
|
||||
if (ddata->disable_on_idle)
|
||||
reset_control_assert(ddata->rsts);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -996,10 +1109,15 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
|
||||
if (ddata->enabled)
|
||||
return 0;
|
||||
|
||||
if (ddata->disable_on_idle)
|
||||
reset_control_deassert(ddata->rsts);
|
||||
|
||||
sysc_clkdm_deny_idle(ddata);
|
||||
|
||||
if (sysc_opt_clks_needed(ddata)) {
|
||||
error = sysc_enable_opt_clocks(ddata);
|
||||
if (error)
|
||||
return error;
|
||||
goto err_allow_idle;
|
||||
}
|
||||
|
||||
error = sysc_enable_main_clocks(ddata);
|
||||
@ -1018,6 +1136,8 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
|
||||
|
||||
ddata->enabled = true;
|
||||
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
|
||||
return 0;
|
||||
|
||||
err_main_clocks:
|
||||
@ -1025,6 +1145,8 @@ err_main_clocks:
|
||||
err_opt_clocks:
|
||||
if (sysc_opt_clks_needed(ddata))
|
||||
sysc_disable_opt_clocks(ddata);
|
||||
err_allow_idle:
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -1106,8 +1228,10 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
0),
|
||||
SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff,
|
||||
0),
|
||||
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
|
||||
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
|
||||
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
|
||||
SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
|
||||
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
|
||||
/* Uarts on omap4 and later */
|
||||
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
|
||||
SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
|
||||
@ -1119,6 +1243,22 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT |
|
||||
SYSC_QUIRK_SWSUP_SIDLE),
|
||||
|
||||
/* Quirks that need to be set based on detected module */
|
||||
SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff,
|
||||
SYSC_MODULE_QUIRK_HDQ1W),
|
||||
SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff,
|
||||
SYSC_MODULE_QUIRK_HDQ1W),
|
||||
SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000036, 0x000000ff,
|
||||
SYSC_MODULE_QUIRK_I2C),
|
||||
SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x0000003c, 0x000000ff,
|
||||
SYSC_MODULE_QUIRK_I2C),
|
||||
SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000040, 0x000000ff,
|
||||
SYSC_MODULE_QUIRK_I2C),
|
||||
SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0,
|
||||
SYSC_MODULE_QUIRK_I2C),
|
||||
SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
|
||||
SYSC_MODULE_QUIRK_WDT),
|
||||
|
||||
#ifdef DEBUG
|
||||
SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
|
||||
SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0),
|
||||
@ -1128,16 +1268,12 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902,
|
||||
0xffff00f0, 0),
|
||||
SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0),
|
||||
SYSC_QUIRK("dcan", 0, 0, -1, -1, 0x00001401, 0xffffffff, 0),
|
||||
SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0),
|
||||
SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
|
||||
SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
|
||||
SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
|
||||
SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0),
|
||||
SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, 0),
|
||||
SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
|
||||
SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
|
||||
SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, 0),
|
||||
SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0),
|
||||
SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
|
||||
SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0),
|
||||
@ -1173,7 +1309,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
|
||||
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
|
||||
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
|
||||
0xffffffff, 0),
|
||||
SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0),
|
||||
SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
|
||||
#endif
|
||||
};
|
||||
@ -1246,6 +1381,121 @@ static void sysc_init_revision_quirks(struct sysc *ddata)
|
||||
}
|
||||
}
|
||||
|
||||
/* 1-wire needs module's internal clocks enabled for reset */
|
||||
static void sysc_clk_enable_quirk_hdq1w(struct sysc *ddata)
|
||||
{
|
||||
int offset = 0x0c; /* HDQ_CTRL_STATUS */
|
||||
u16 val;
|
||||
|
||||
val = sysc_read(ddata, offset);
|
||||
val |= BIT(5);
|
||||
sysc_write(ddata, offset, val);
|
||||
}
|
||||
|
||||
/* I2C needs extra enable bit toggling for reset */
|
||||
static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable)
|
||||
{
|
||||
int offset;
|
||||
u16 val;
|
||||
|
||||
/* I2C_CON, omap2/3 is different from omap4 and later */
|
||||
if ((ddata->revision & 0xffffff00) == 0x001f0000)
|
||||
offset = 0x24;
|
||||
else
|
||||
offset = 0xa4;
|
||||
|
||||
/* I2C_EN */
|
||||
val = sysc_read(ddata, offset);
|
||||
if (enable)
|
||||
val |= BIT(15);
|
||||
else
|
||||
val &= ~BIT(15);
|
||||
sysc_write(ddata, offset, val);
|
||||
}
|
||||
|
||||
static void sysc_clk_enable_quirk_i2c(struct sysc *ddata)
|
||||
{
|
||||
sysc_clk_quirk_i2c(ddata, true);
|
||||
}
|
||||
|
||||
static void sysc_clk_disable_quirk_i2c(struct sysc *ddata)
|
||||
{
|
||||
sysc_clk_quirk_i2c(ddata, false);
|
||||
}
|
||||
|
||||
/* Watchdog timer needs a disable sequence after reset */
|
||||
static void sysc_reset_done_quirk_wdt(struct sysc *ddata)
|
||||
{
|
||||
int wps, spr, error;
|
||||
u32 val;
|
||||
|
||||
wps = 0x34;
|
||||
spr = 0x48;
|
||||
|
||||
sysc_write(ddata, spr, 0xaaaa);
|
||||
error = readl_poll_timeout(ddata->module_va + wps, val,
|
||||
!(val & 0x10), 100,
|
||||
MAX_MODULE_SOFTRESET_WAIT);
|
||||
if (error)
|
||||
dev_warn(ddata->dev, "wdt disable spr failed\n");
|
||||
|
||||
sysc_write(ddata, wps, 0x5555);
|
||||
error = readl_poll_timeout(ddata->module_va + wps, val,
|
||||
!(val & 0x10), 100,
|
||||
MAX_MODULE_SOFTRESET_WAIT);
|
||||
if (error)
|
||||
dev_warn(ddata->dev, "wdt disable wps failed\n");
|
||||
}
|
||||
|
||||
static void sysc_init_module_quirks(struct sysc *ddata)
|
||||
{
|
||||
if (ddata->legacy_mode || !ddata->name)
|
||||
return;
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) {
|
||||
ddata->clk_enable_quirk = sysc_clk_enable_quirk_hdq1w;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) {
|
||||
ddata->clk_enable_quirk = sysc_clk_enable_quirk_i2c;
|
||||
ddata->clk_disable_quirk = sysc_clk_disable_quirk_i2c;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_WDT)
|
||||
ddata->reset_done_quirk = sysc_reset_done_quirk_wdt;
|
||||
}
|
||||
|
||||
static int sysc_clockdomain_init(struct sysc *ddata)
|
||||
{
|
||||
struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
|
||||
struct clk *fck = NULL, *ick = NULL;
|
||||
int error;
|
||||
|
||||
if (!pdata || !pdata->init_clockdomain)
|
||||
return 0;
|
||||
|
||||
switch (ddata->nr_clocks) {
|
||||
case 2:
|
||||
ick = ddata->clocks[SYSC_ICK];
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
fck = ddata->clocks[SYSC_FCK];
|
||||
break;
|
||||
case 0:
|
||||
return 0;
|
||||
}
|
||||
|
||||
error = pdata->init_clockdomain(ddata->dev, fck, ick, &ddata->cookie);
|
||||
if (!error || error == -ENODEV)
|
||||
return 0;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that pdata->init_module() typically does a reset first. After
|
||||
* pdata->init_module() is done, PM runtime can be used for the interconnect
|
||||
@ -1256,7 +1506,7 @@ static int sysc_legacy_init(struct sysc *ddata)
|
||||
struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
|
||||
int error;
|
||||
|
||||
if (!ddata->legacy_mode || !pdata || !pdata->init_module)
|
||||
if (!pdata || !pdata->init_module)
|
||||
return 0;
|
||||
|
||||
error = pdata->init_module(ddata->dev, ddata->mdata, &ddata->cookie);
|
||||
@ -1281,7 +1531,7 @@ static int sysc_legacy_init(struct sysc *ddata)
|
||||
*/
|
||||
static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset)
|
||||
{
|
||||
int error;
|
||||
int error, val;
|
||||
|
||||
if (!ddata->rsts)
|
||||
return 0;
|
||||
@ -1292,37 +1542,68 @@ static int sysc_rstctrl_reset_deassert(struct sysc *ddata, bool reset)
|
||||
return error;
|
||||
}
|
||||
|
||||
return reset_control_deassert(ddata->rsts);
|
||||
error = reset_control_deassert(ddata->rsts);
|
||||
if (error == -EEXIST)
|
||||
return 0;
|
||||
|
||||
error = readx_poll_timeout(reset_control_status, ddata->rsts, val,
|
||||
val == 0, 100, MAX_MODULE_SOFTRESET_WAIT);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that the caller must ensure the interconnect target module is enabled
|
||||
* before calling reset. Otherwise reset will not complete.
|
||||
*/
|
||||
static int sysc_reset(struct sysc *ddata)
|
||||
{
|
||||
int offset = ddata->offsets[SYSC_SYSCONFIG];
|
||||
int val;
|
||||
int sysc_offset, syss_offset, sysc_val, rstval, quirks, error = 0;
|
||||
u32 sysc_mask, syss_done;
|
||||
|
||||
if (ddata->legacy_mode || offset < 0 ||
|
||||
sysc_offset = ddata->offsets[SYSC_SYSCONFIG];
|
||||
syss_offset = ddata->offsets[SYSC_SYSSTATUS];
|
||||
quirks = ddata->cfg.quirks;
|
||||
|
||||
if (ddata->legacy_mode || sysc_offset < 0 ||
|
||||
ddata->cap->regbits->srst_shift < 0 ||
|
||||
ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Currently only support reset status in sysstatus.
|
||||
* Warn and return error in all other cases
|
||||
*/
|
||||
if (!ddata->cfg.syss_mask) {
|
||||
dev_err(ddata->dev, "No ti,syss-mask. Reset failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
sysc_mask = BIT(ddata->cap->regbits->srst_shift);
|
||||
|
||||
val = sysc_read(ddata, offset);
|
||||
val |= (0x1 << ddata->cap->regbits->srst_shift);
|
||||
sysc_write(ddata, offset, val);
|
||||
if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED)
|
||||
syss_done = 0;
|
||||
else
|
||||
syss_done = ddata->cfg.syss_mask;
|
||||
|
||||
if (ddata->clk_disable_quirk)
|
||||
ddata->clk_disable_quirk(ddata);
|
||||
|
||||
sysc_val = sysc_read_sysconfig(ddata);
|
||||
sysc_val |= sysc_mask;
|
||||
sysc_write(ddata, sysc_offset, sysc_val);
|
||||
|
||||
if (ddata->clk_enable_quirk)
|
||||
ddata->clk_enable_quirk(ddata);
|
||||
|
||||
/* Poll on reset status */
|
||||
offset = ddata->offsets[SYSC_SYSSTATUS];
|
||||
if (syss_offset >= 0) {
|
||||
error = readx_poll_timeout(sysc_read_sysstatus, ddata, rstval,
|
||||
(rstval & ddata->cfg.syss_mask) ==
|
||||
syss_done,
|
||||
100, MAX_MODULE_SOFTRESET_WAIT);
|
||||
|
||||
return readl_poll_timeout(ddata->module_va + offset, val,
|
||||
(val & ddata->cfg.syss_mask) == 0x0,
|
||||
100, MAX_MODULE_SOFTRESET_WAIT);
|
||||
} else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) {
|
||||
error = readx_poll_timeout(sysc_read_sysconfig, ddata, rstval,
|
||||
!(rstval & sysc_mask),
|
||||
100, MAX_MODULE_SOFTRESET_WAIT);
|
||||
}
|
||||
|
||||
if (ddata->reset_done_quirk)
|
||||
ddata->reset_done_quirk(ddata);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1335,12 +1616,8 @@ static int sysc_init_module(struct sysc *ddata)
|
||||
{
|
||||
int error = 0;
|
||||
bool manage_clocks = true;
|
||||
bool reset = true;
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
|
||||
reset = false;
|
||||
|
||||
error = sysc_rstctrl_reset_deassert(ddata, reset);
|
||||
error = sysc_rstctrl_reset_deassert(ddata, false);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@ -1348,7 +1625,13 @@ static int sysc_init_module(struct sysc *ddata)
|
||||
(SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))
|
||||
manage_clocks = false;
|
||||
|
||||
error = sysc_clockdomain_init(ddata);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (manage_clocks) {
|
||||
sysc_clkdm_deny_idle(ddata);
|
||||
|
||||
error = sysc_enable_opt_clocks(ddata);
|
||||
if (error)
|
||||
return error;
|
||||
@ -1358,23 +1641,43 @@ static int sysc_init_module(struct sysc *ddata)
|
||||
goto err_opt_clocks;
|
||||
}
|
||||
|
||||
if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) {
|
||||
error = sysc_rstctrl_reset_deassert(ddata, true);
|
||||
if (error)
|
||||
goto err_main_clocks;
|
||||
}
|
||||
|
||||
ddata->revision = sysc_read_revision(ddata);
|
||||
sysc_init_revision_quirks(ddata);
|
||||
sysc_init_module_quirks(ddata);
|
||||
|
||||
error = sysc_legacy_init(ddata);
|
||||
if (error)
|
||||
goto err_main_clocks;
|
||||
if (ddata->legacy_mode) {
|
||||
error = sysc_legacy_init(ddata);
|
||||
if (error)
|
||||
goto err_main_clocks;
|
||||
}
|
||||
|
||||
if (!ddata->legacy_mode && manage_clocks) {
|
||||
error = sysc_enable_module(ddata->dev);
|
||||
if (error)
|
||||
goto err_main_clocks;
|
||||
}
|
||||
|
||||
error = sysc_reset(ddata);
|
||||
if (error)
|
||||
dev_err(ddata->dev, "Reset failed with %d\n", error);
|
||||
|
||||
if (!ddata->legacy_mode && manage_clocks)
|
||||
sysc_disable_module(ddata->dev);
|
||||
|
||||
err_main_clocks:
|
||||
if (manage_clocks)
|
||||
sysc_disable_main_clocks(ddata);
|
||||
err_opt_clocks:
|
||||
if (manage_clocks)
|
||||
if (manage_clocks) {
|
||||
sysc_disable_opt_clocks(ddata);
|
||||
sysc_clkdm_allow_idle(ddata);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -1664,9 +1967,6 @@ static struct dev_pm_domain sysc_child_pm_domain = {
|
||||
*/
|
||||
static void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child)
|
||||
{
|
||||
if (!ddata->legacy_mode)
|
||||
return;
|
||||
|
||||
if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
|
||||
dev_pm_domain_set(child, &sysc_child_pm_domain);
|
||||
}
|
||||
@ -2006,6 +2306,7 @@ static const struct sysc_capabilities sysc_dra7_mcan = {
|
||||
.type = TI_SYSC_DRA7_MCAN,
|
||||
.sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET,
|
||||
.regbits = &sysc_regbits_dra7_mcan,
|
||||
.mod_quirks = SYSS_QUIRK_RESETDONE_INVERTED,
|
||||
};
|
||||
|
||||
static int sysc_init_pdata(struct sysc *ddata)
|
||||
@ -2013,20 +2314,22 @@ static int sysc_init_pdata(struct sysc *ddata)
|
||||
struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev);
|
||||
struct ti_sysc_module_data *mdata;
|
||||
|
||||
if (!pdata || !ddata->legacy_mode)
|
||||
if (!pdata)
|
||||
return 0;
|
||||
|
||||
mdata = devm_kzalloc(ddata->dev, sizeof(*mdata), GFP_KERNEL);
|
||||
if (!mdata)
|
||||
return -ENOMEM;
|
||||
|
||||
mdata->name = ddata->legacy_mode;
|
||||
mdata->module_pa = ddata->module_pa;
|
||||
mdata->module_size = ddata->module_size;
|
||||
mdata->offsets = ddata->offsets;
|
||||
mdata->nr_offsets = SYSC_MAX_REGS;
|
||||
mdata->cap = ddata->cap;
|
||||
mdata->cfg = &ddata->cfg;
|
||||
if (ddata->legacy_mode) {
|
||||
mdata->name = ddata->legacy_mode;
|
||||
mdata->module_pa = ddata->module_pa;
|
||||
mdata->module_size = ddata->module_size;
|
||||
mdata->offsets = ddata->offsets;
|
||||
mdata->nr_offsets = SYSC_MAX_REGS;
|
||||
mdata->cap = ddata->cap;
|
||||
mdata->cfg = &ddata->cfg;
|
||||
}
|
||||
|
||||
ddata->mdata = mdata;
|
||||
|
||||
@ -2146,7 +2449,7 @@ static int sysc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (!of_get_available_child_count(ddata->dev->of_node))
|
||||
reset_control_assert(ddata->rsts);
|
||||
ddata->disable_on_idle = true;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -19,6 +19,7 @@ enum ti_sysc_module_type {
|
||||
|
||||
struct ti_sysc_cookie {
|
||||
void *data;
|
||||
void *clkdm;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -46,6 +47,10 @@ struct sysc_regbits {
|
||||
s8 emufree_shift;
|
||||
};
|
||||
|
||||
#define SYSC_MODULE_QUIRK_HDQ1W BIT(17)
|
||||
#define SYSC_MODULE_QUIRK_I2C BIT(16)
|
||||
#define SYSC_MODULE_QUIRK_WDT BIT(15)
|
||||
#define SYSS_QUIRK_RESETDONE_INVERTED BIT(14)
|
||||
#define SYSC_QUIRK_SWSUP_MSTANDBY BIT(13)
|
||||
#define SYSC_QUIRK_SWSUP_SIDLE_ACT BIT(12)
|
||||
#define SYSC_QUIRK_SWSUP_SIDLE BIT(11)
|
||||
@ -125,9 +130,16 @@ struct ti_sysc_module_data {
|
||||
};
|
||||
|
||||
struct device;
|
||||
struct clk;
|
||||
|
||||
struct ti_sysc_platform_data {
|
||||
struct of_dev_auxdata *auxdata;
|
||||
int (*init_clockdomain)(struct device *dev, struct clk *fck,
|
||||
struct clk *ick, struct ti_sysc_cookie *cookie);
|
||||
void (*clkdm_deny_idle)(struct device *dev,
|
||||
const struct ti_sysc_cookie *cookie);
|
||||
void (*clkdm_allow_idle)(struct device *dev,
|
||||
const struct ti_sysc_cookie *cookie);
|
||||
int (*init_module)(struct device *dev,
|
||||
const struct ti_sysc_module_data *data,
|
||||
struct ti_sysc_cookie *cookie);
|
||||
|
Loading…
Reference in New Issue
Block a user