diff mbox series

[v3] soc: rockchip: io-domain: set 3.3V before regulator disable

Message ID 20210818010956.1446770-1-jay.xu@rock-chips.com (mailing list archive)
State New, archived
Headers show
Series [v3] soc: rockchip: io-domain: set 3.3V before regulator disable | expand

Commit Message

Jianqun Xu Aug. 18, 2021, 1:09 a.m. UTC
Do a fix to rockchip io-domain, follow this orders:

* system running state
  -> io-domain vsel to 3.3V (actually is done by pre-disable)
    -> regulator_enable
      -> vsel change according to regulator voltage

* system running state
  -> io-domain vsel to 3.3V
    -> regulator_disable

Found on some Rockchip SoCs, the regulator enable or disable without
care about the io-domain maybe caused soc damaged.

Tested on RV1126 EVB.

Signed-off-by: Jianqun Xu <jay.xu@rock-chips.com>
---
v3:
 - abandon PRE-ENABLE patch
 - delete the EVENT_PRE_ENABLE case
v2: none
v1: first version

 drivers/soc/rockchip/io-domain.c | 6 ++++++
 1 file changed, 6 insertions(+)

Comments

kernel test robot Aug. 18, 2021, 5:11 a.m. UTC | #1
Hi Jianqun,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on asoc/for-next v5.14-rc6 next-20210817]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jianqun-Xu/soc-rockchip-io-domain-set-3-3V-before-regulator-disable/20210818-091213
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: arm64-randconfig-r011-20210816 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project af7818093677dcb4c0840aef96bc029deb219e57)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/0day-ci/linux/commit/883d33a4052a54385679fe84a17345d7083f3a76
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jianqun-Xu/soc-rockchip-io-domain-set-3-3V-before-regulator-disable/20210818-091213
        git checkout 883d33a4052a54385679fe84a17345d7083f3a76
        # save the attached .config to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/soc/rockchip/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/soc/rockchip/io-domain.c:173:21: error: use of undeclared identifier 'REGULATOR_EVENT_PRE_ENABLE'
           } else if (event & REGULATOR_EVENT_PRE_ENABLE) {
                              ^
   1 error generated.


vim +/REGULATOR_EVENT_PRE_ENABLE +173 drivers/soc/rockchip/io-domain.c

   143	
   144	static int rockchip_iodomain_notify(struct notifier_block *nb,
   145					    unsigned long event,
   146					    void *data)
   147	{
   148		struct rockchip_iodomain_supply *supply =
   149				container_of(nb, struct rockchip_iodomain_supply, nb);
   150		int uV;
   151		int ret;
   152	
   153		/*
   154		 * According to Rockchip it's important to keep the SoC IO domain
   155		 * higher than (or equal to) the external voltage.  That means we need
   156		 * to change it before external voltage changes happen in the case
   157		 * of an increase.
   158		 *
   159		 * Note that in the "pre" change we pick the max possible voltage that
   160		 * the regulator might end up at (the client requests a range and we
   161		 * don't know for certain the exact voltage).  Right now we rely on the
   162		 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
   163		 * request something like a max of 3.6V when they really want 3.3V.
   164		 * We could attempt to come up with better rules if this fails.
   165		 */
   166		if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
   167			struct pre_voltage_change_data *pvc_data = data;
   168	
   169			uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
   170		} else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
   171				    REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
   172			uV = (unsigned long)data;
 > 173		} else if (event & REGULATOR_EVENT_PRE_ENABLE) {
   174			uV = MAX_VOLTAGE_3_3;
   175		} else if (event & REGULATOR_EVENT_PRE_DISABLE) {
   176			uV = MAX_VOLTAGE_3_3;
   177		} else if (event & REGULATOR_EVENT_ENABLE) {
   178			uV = regulator_get_voltage(supply->reg);
   179		} else {
   180			return NOTIFY_OK;
   181		}
   182	
   183		dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
   184	
   185		if (uV > MAX_VOLTAGE_3_3) {
   186			dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
   187	
   188			if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
   189				return NOTIFY_BAD;
   190		}
   191	
   192		ret = supply->iod->write(supply, uV);
   193		if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
   194			return NOTIFY_BAD;
   195	
   196		dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
   197		return NOTIFY_OK;
   198	}
   199	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Aug. 18, 2021, 5:56 a.m. UTC | #2
Hi Jianqun,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on rockchip/for-next]
[also build test ERROR on asoc/for-next v5.14-rc6 next-20210817]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jianqun-Xu/soc-rockchip-io-domain-set-3-3V-before-regulator-disable/20210818-091213
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
config: arm-defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/883d33a4052a54385679fe84a17345d7083f3a76
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jianqun-Xu/soc-rockchip-io-domain-set-3-3V-before-regulator-disable/20210818-091213
        git checkout 883d33a4052a54385679fe84a17345d7083f3a76
        # save the attached .config to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arm SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/soc/rockchip/io-domain.c: In function 'rockchip_iodomain_notify':
>> drivers/soc/rockchip/io-domain.c:173:28: error: 'REGULATOR_EVENT_PRE_ENABLE' undeclared (first use in this function); did you mean 'REGULATOR_EVENT_PRE_DISABLE'?
     173 |         } else if (event & REGULATOR_EVENT_PRE_ENABLE) {
         |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~
         |                            REGULATOR_EVENT_PRE_DISABLE
   drivers/soc/rockchip/io-domain.c:173:28: note: each undeclared identifier is reported only once for each function it appears in


vim +173 drivers/soc/rockchip/io-domain.c

   143	
   144	static int rockchip_iodomain_notify(struct notifier_block *nb,
   145					    unsigned long event,
   146					    void *data)
   147	{
   148		struct rockchip_iodomain_supply *supply =
   149				container_of(nb, struct rockchip_iodomain_supply, nb);
   150		int uV;
   151		int ret;
   152	
   153		/*
   154		 * According to Rockchip it's important to keep the SoC IO domain
   155		 * higher than (or equal to) the external voltage.  That means we need
   156		 * to change it before external voltage changes happen in the case
   157		 * of an increase.
   158		 *
   159		 * Note that in the "pre" change we pick the max possible voltage that
   160		 * the regulator might end up at (the client requests a range and we
   161		 * don't know for certain the exact voltage).  Right now we rely on the
   162		 * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
   163		 * request something like a max of 3.6V when they really want 3.3V.
   164		 * We could attempt to come up with better rules if this fails.
   165		 */
   166		if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
   167			struct pre_voltage_change_data *pvc_data = data;
   168	
   169			uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
   170		} else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
   171				    REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
   172			uV = (unsigned long)data;
 > 173		} else if (event & REGULATOR_EVENT_PRE_ENABLE) {
   174			uV = MAX_VOLTAGE_3_3;
   175		} else if (event & REGULATOR_EVENT_PRE_DISABLE) {
   176			uV = MAX_VOLTAGE_3_3;
   177		} else if (event & REGULATOR_EVENT_ENABLE) {
   178			uV = regulator_get_voltage(supply->reg);
   179		} else {
   180			return NOTIFY_OK;
   181		}
   182	
   183		dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
   184	
   185		if (uV > MAX_VOLTAGE_3_3) {
   186			dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
   187	
   188			if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
   189				return NOTIFY_BAD;
   190		}
   191	
   192		ret = supply->iod->write(supply, uV);
   193		if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
   194			return NOTIFY_BAD;
   195	
   196		dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
   197		return NOTIFY_OK;
   198	}
   199	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Mark Brown Aug. 18, 2021, 12:27 p.m. UTC | #3
On Wed, Aug 18, 2021 at 09:09:56AM +0800, Jianqun Xu wrote:

> +	} else if (event & REGULATOR_EVENT_ENABLE) {
> +		uV = regulator_get_voltage(supply->reg);

I'm still not clear that the locking is safe here - the notifier is
called with the regulator lock held but regulator_get_voltage() wants to
take that lock.  Have you tried this with the various lock debugging
stuff turned on?
diff mbox series

Patch

diff --git a/drivers/soc/rockchip/io-domain.c b/drivers/soc/rockchip/io-domain.c
index cf8182fc3642..3c59077fafb1 100644
--- a/drivers/soc/rockchip/io-domain.c
+++ b/drivers/soc/rockchip/io-domain.c
@@ -123,6 +123,12 @@  static int rockchip_iodomain_notify(struct notifier_block *nb,
 	} else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
 			    REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
 		uV = (unsigned long)data;
+	} else if (event & REGULATOR_EVENT_PRE_ENABLE) {
+		uV = MAX_VOLTAGE_3_3;
+	} else if (event & REGULATOR_EVENT_PRE_DISABLE) {
+		uV = MAX_VOLTAGE_3_3;
+	} else if (event & REGULATOR_EVENT_ENABLE) {
+		uV = regulator_get_voltage(supply->reg);
 	} else {
 		return NOTIFY_OK;
 	}