Home | History | Annotate | Line # | Download | only in bootimx23
      1 /* $Id: power_prep.c,v 1.5 2016/08/17 22:04:51 skrll Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Petri Laakso.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #include <sys/param.h>
     34 #include <sys/types.h>
     35 
     36 #include <arm/imx/imx23_powerreg.h>
     37 
     38 #include <lib/libkern/libkern.h>
     39 #include <lib/libsa/stand.h>
     40 
     41 #include "common.h"
     42 
     43 #define PWR_CTRL	(HW_POWER_BASE + HW_POWER_CTRL)
     44 #define PWR_CTRL_S	(HW_POWER_BASE + HW_POWER_CTRL_SET)
     45 #define PWR_CTRL_C	(HW_POWER_BASE + HW_POWER_CTRL_CLR)
     46 #define PWR_5VCTRL	(HW_POWER_BASE + HW_POWER_5VCTRL)
     47 #define PWR_5VCTRL_S	(HW_POWER_BASE + HW_POWER_5VCTRL_SET)
     48 #define PWR_5VCTRL_C	(HW_POWER_BASE + HW_POWER_5VCTRL_CLR)
     49 #define PWR_MINPWR	(HW_POWER_BASE + HW_POWER_MINPWR)
     50 #define PWR_MINPWR_S	(HW_POWER_BASE + HW_POWER_MINPWR_SET)
     51 #define PWR_MINPWR_C	(HW_POWER_BASE + HW_POWER_MINPWR_CLR)
     52 #define PWR_CHARGE	(HW_POWER_BASE + HW_POWER_CHARGE)
     53 #define PWR_CHARGE_S	(HW_POWER_BASE + HW_POWER_CHARGE_SET)
     54 #define PWR_CHARGE_C	(HW_POWER_BASE + HW_POWER_CHARGE_CLR)
     55 #define PWR_VDDDCTRL	(HW_POWER_BASE + HW_POWER_VDDDCTRL)
     56 #define PWR_VDDACTRL	(HW_POWER_BASE + HW_POWER_VDDACTRL)
     57 #define PWR_VDDIOCTRL	(HW_POWER_BASE + HW_POWER_VDDIOCTRL)
     58 #define PWR_VDDMEMCTRL	(HW_POWER_BASE + HW_POWER_VDDMEMCTRL)
     59 #define PWR_DCDC4P2	(HW_POWER_BASE + HW_POWER_DCDC4P2)
     60 #define PWR_MISC	(HW_POWER_BASE + HW_POWER_MISC)
     61 #define PWR_DCLIMITS	(HW_POWER_BASE + HW_POWER_DCLIMITS)
     62 #define PWR_LOOPCTRL 	(HW_POWER_BASE + HW_POWER_LOOPCTRL)
     63 #define PWR_LOOPCTRL_S	(HW_POWER_BASE + HW_POWER_LOOPCTRL_SET)
     64 #define PWR_LOOPCTRL_C	(HW_POWER_BASE + HW_POWER_LOOPCTRL_CLR)
     65 #define PWR_STATUS	(HW_POWER_BASE + HW_POWER_STS)
     66 #define PWR_SPEED	(HW_POWER_BASE + HW_POWER_SPEED)
     67 #define PWR_BATTMONITOR	(HW_POWER_BASE + HW_POWER_BATTMONITOR)
     68 #define PWR_RESET	(HW_POWER_BASE + HW_POWER_RESET)
     69 #define PWR_DEBUG	(HW_POWER_BASE + HW_POWER_DEBUG)
     70 #define PWR_SPECIAL	(HW_POWER_BASE + HW_POWER_SPECIAL)
     71 #define PWR_VERSION	(HW_POWER_BASE + HW_POWER_VERSION)
     72 
     73 #define VBUSVALID_TRSH 5	/* 4.4V */
     74 #define CHARGE_4P2_ILIMIT_MAX 0x3f
     75 #define CMPTRIP 0x1f	/* DCDC_4P2 pin >= 1.05 * BATTERY pin. */
     76 #define DROPOUT_CTRL 0xa /* BO 100mV, DCDC selects higher. */
     77 
     78 void en_vbusvalid(void);
     79 int vbusvalid(void);
     80 void power_tune(void);
     81 void en_4p2_reg(void);
     82 void en_4p2_to_dcdc(void);
     83 void power_vddd_from_dcdc(int, int);
     84 void power_vdda_from_dcdc(int, int);
     85 void power_vddio_from_dcdc(int, int);
     86 void power_vddmem(int);
     87 
     88 /*
     89  * Configure the DCDC control logic 5V detection to use VBUSVALID.
     90  */
     91 void
     92 en_vbusvalid(void)
     93 {
     94 	uint32_t tmp_r;
     95 
     96 	tmp_r = REG_RD(PWR_5VCTRL);
     97 	tmp_r &= ~HW_POWER_5VCTRL_VBUSVALID_TRSH;
     98 	tmp_r |= __SHIFTIN(VBUSVALID_TRSH, HW_POWER_5VCTRL_VBUSVALID_TRSH);
     99 	REG_WR(PWR_5VCTRL, tmp_r);
    100 
    101 	REG_WR(PWR_5VCTRL_S, HW_POWER_5VCTRL_PWRUP_VBUS_CMPS);
    102 	delay(1000);
    103 
    104 	REG_WR(PWR_5VCTRL_S, HW_POWER_5VCTRL_VBUSVALID_5VDETECT);
    105 
    106 	return;
    107 }
    108 /*
    109  * Test VBUSVALID.
    110  */
    111 int
    112 vbusvalid(void)
    113 {
    114 	if (REG_RD(PWR_STATUS) & HW_POWER_STS_VBUSVALID)
    115 		return 1;
    116 	else
    117 		return 0;
    118 }
    119 /*
    120  * Set various registers.
    121  */
    122 void
    123 power_tune(void)
    124 {
    125 	uint32_t tmp_r;
    126 
    127 	REG_WR(PWR_LOOPCTRL_S, HW_POWER_LOOPCTRL_TOGGLE_DIF |
    128 		HW_POWER_LOOPCTRL_EN_CM_HYST |
    129 		HW_POWER_LOOPCTRL_EN_DF_HYST |
    130 		HW_POWER_LOOPCTRL_RCSCALE_THRESH |
    131 		__SHIFTIN(3, HW_POWER_LOOPCTRL_EN_RCSCALE));
    132 
    133 	REG_WR(PWR_MINPWR_S, HW_POWER_MINPWR_DOUBLE_FETS);
    134 
    135 	REG_WR(PWR_5VCTRL_S, __SHIFTIN(4, HW_POWER_5VCTRL_HEADROOM_ADJ));
    136 
    137 	tmp_r = REG_RD(PWR_DCLIMITS);
    138 	tmp_r &= ~HW_POWER_DCLIMITS_POSLIMIT_BUCK;
    139 	tmp_r |= __SHIFTIN(0x30, HW_POWER_DCLIMITS_POSLIMIT_BUCK);
    140 	REG_WR(PWR_DCLIMITS, tmp_r);
    141 
    142 	return;
    143 }
    144 /*
    145  * AN3883.pdf 2.1.3.1 Enabling the 4P2 LinReg
    146  */
    147 void
    148 en_4p2_reg(void)
    149 {
    150 	uint32_t tmp_r;
    151 	int ilimit;
    152 
    153 	/* TRG is 4.2V by default. */
    154 	tmp_r = REG_RD(PWR_DCDC4P2);
    155 	tmp_r |= HW_POWER_DCDC4P2_ENABLE_4P2;
    156 	REG_WR(PWR_DCDC4P2, tmp_r);
    157 
    158 	REG_WR(PWR_CHARGE_S, HW_POWER_CHARGE_ENABLE_LOAD);
    159 
    160 	/* Set CHARGE_4P2_ILIMIT to minimum. */
    161 	REG_WR(PWR_5VCTRL_C, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT);
    162 	REG_WR(PWR_5VCTRL_S, __SHIFTIN(1, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT));
    163 
    164 	/* Power up 4.2V regulation circuit. */
    165 	REG_WR(PWR_5VCTRL_C, HW_POWER_5VCTRL_PWD_CHARGE_4P2);
    166 
    167 	/* Ungate path from 4P2 reg to DCDC. */
    168 	tmp_r = REG_RD(PWR_DCDC4P2);
    169 	tmp_r |= HW_POWER_DCDC4P2_ENABLE_DCDC;
    170 	REG_WR(PWR_DCDC4P2, tmp_r);
    171 
    172 	delay(10000);
    173 
    174 	/* Charge 4P2 capacitance. */
    175 	tmp_r = REG_RD(PWR_5VCTRL);
    176 	for (ilimit = 2; ilimit <= CHARGE_4P2_ILIMIT_MAX; ilimit++) {
    177 		tmp_r &= ~HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT;
    178 		tmp_r |= __SHIFTIN(ilimit, HW_POWER_5VCTRL_CHARGE_4P2_ILIMIT);
    179 		REG_WR(PWR_5VCTRL, tmp_r);
    180 		delay(10000);
    181 	}
    182 
    183 	return;
    184 }
    185 
    186 /*
    187  * AN3883.pdf 2.1.3.3 Enabling 4P2 Input to DC-DC
    188  */
    189 void en_4p2_to_dcdc(void)
    190 {
    191 	uint32_t tmp_r;
    192 
    193 	tmp_r = REG_RD(PWR_DCDC4P2);
    194 
    195 	tmp_r &= ~HW_POWER_DCDC4P2_CMPTRIP;
    196 	tmp_r |= __SHIFTIN(CMPTRIP, HW_POWER_DCDC4P2_CMPTRIP);
    197 
    198 	tmp_r &= ~HW_POWER_DCDC4P2_DROPOUT_CTRL;
    199 	tmp_r |= __SHIFTIN(DROPOUT_CTRL, HW_POWER_DCDC4P2_DROPOUT_CTRL);
    200 
    201 	REG_WR(PWR_DCDC4P2, tmp_r);
    202 
    203 	REG_WR(PWR_5VCTRL_C, HW_POWER_5VCTRL_DCDC_XFER);
    204 
    205 	/* Enabling DCDC triggers 5V brownout. */
    206 	REG_WR(PWR_5VCTRL_C, HW_POWER_5VCTRL_PWDN_5VBRNOUT);
    207 	REG_WR(PWR_5VCTRL_S, HW_POWER_5VCTRL_ENABLE_DCDC);
    208 	delay(10000);
    209 	REG_WR(PWR_5VCTRL_S, HW_POWER_5VCTRL_PWDN_5VBRNOUT);
    210 
    211 	/* Now DCDC is using 4P2 so I can remove extra temporary load. */
    212 	REG_WR(PWR_CHARGE_C, HW_POWER_CHARGE_ENABLE_LOAD);
    213 
    214 	return;
    215 }
    216 
    217 /*
    218  * Configure VDDD to source power from DCDC.
    219  */
    220 void
    221 power_vddd_from_dcdc(int target, int brownout)
    222 {
    223 	uint32_t tmp_r;
    224 
    225 	/* BO_OFFSET must be within 800mV - 1475mV */
    226 	if (brownout > 1475)
    227 		brownout = 1475;
    228 	else if (brownout < 800)
    229 		brownout = 800;
    230 
    231 
    232 	/* Set LINREG_OFFSET one step below TRG. */
    233 	tmp_r = REG_RD(PWR_VDDDCTRL);
    234 	tmp_r &= ~HW_POWER_VDDDCTRL_LINREG_OFFSET;
    235 	tmp_r |= __SHIFTIN(2, HW_POWER_VDDDCTRL_LINREG_OFFSET);
    236 	REG_WR(PWR_VDDDCTRL, tmp_r);
    237 	delay(10000);
    238 
    239 	/* Enable VDDD switching converter output. */
    240 	tmp_r = REG_RD(PWR_VDDDCTRL);
    241 	tmp_r &= ~HW_POWER_VDDDCTRL_DISABLE_FET;
    242 	REG_WR(PWR_VDDDCTRL, tmp_r);
    243 	delay(10000);
    244 
    245 	/* Disable linear regulator output. */
    246 	tmp_r = REG_RD(PWR_VDDDCTRL);
    247 	tmp_r &= ~HW_POWER_VDDDCTRL_ENABLE_LINREG;
    248 	REG_WR(PWR_VDDDCTRL, tmp_r);
    249 	delay(10000);
    250 
    251 	/* Set target voltage and brownout level. */
    252 	tmp_r = REG_RD(PWR_VDDDCTRL);
    253 	tmp_r &= ~(HW_POWER_VDDDCTRL_BO_OFFSET | HW_POWER_VDDDCTRL_TRG);
    254 	tmp_r |= __SHIFTIN(((target - brownout) / 25),
    255 		HW_POWER_VDDDCTRL_BO_OFFSET);
    256 	tmp_r |= __SHIFTIN(((target - 800) / 25), HW_POWER_VDDDCTRL_TRG);
    257 	REG_WR(PWR_VDDDCTRL, tmp_r);
    258 	delay(10000);
    259 
    260 	/* Enable PWDN_BRNOUT. */
    261 	REG_WR(PWR_CTRL_C, HW_POWER_CTRL_VDDD_BO_IRQ);
    262 
    263 	tmp_r = REG_RD(PWR_VDDDCTRL);
    264 	tmp_r |= HW_POWER_VDDDCTRL_PWDN_BRNOUT;
    265 	REG_WR(PWR_VDDDCTRL, tmp_r);
    266 
    267 	return;
    268 }
    269 /*
    270  * Configure VDDA to source power from DCDC.
    271  */
    272 void
    273 power_vdda_from_dcdc(int target, int brownout)
    274 {
    275 	uint32_t tmp_r;
    276 
    277 	/* BO_OFFSET must be within 1400mV - 2175mV */
    278 	if (brownout > 2275)
    279 		brownout = 2275;
    280 	else if (brownout < 1400)
    281 		brownout = 1400;
    282 
    283 
    284 	/* Set LINREG_OFFSET one step below TRG. */
    285 	tmp_r = REG_RD(PWR_VDDACTRL);
    286 	tmp_r &= ~HW_POWER_VDDACTRL_LINREG_OFFSET;
    287 	tmp_r |= __SHIFTIN(2, HW_POWER_VDDACTRL_LINREG_OFFSET);
    288 	REG_WR(PWR_VDDACTRL, tmp_r);
    289 	delay(10000);
    290 
    291 	/* Enable VDDA switching converter output. */
    292 	tmp_r = REG_RD(PWR_VDDACTRL);
    293 	tmp_r &= ~HW_POWER_VDDACTRL_DISABLE_FET;
    294 	REG_WR(PWR_VDDACTRL, tmp_r);
    295 	delay(10000);
    296 
    297 	/* Disable linear regulator output. */
    298 	tmp_r = REG_RD(PWR_VDDACTRL);
    299 	tmp_r &= ~HW_POWER_VDDACTRL_ENABLE_LINREG;
    300 	REG_WR(PWR_VDDACTRL, tmp_r);
    301 	delay(10000);
    302 
    303 	/* Set target voltage and brownout level. */
    304 	tmp_r = REG_RD(PWR_VDDACTRL);
    305 	tmp_r &= ~(HW_POWER_VDDACTRL_BO_OFFSET | HW_POWER_VDDACTRL_TRG);
    306 	tmp_r |= __SHIFTIN(((target - brownout) / 25),
    307 		HW_POWER_VDDACTRL_BO_OFFSET);
    308 	tmp_r |= __SHIFTIN(((target - 1500) / 25), HW_POWER_VDDACTRL_TRG);
    309 	REG_WR(PWR_VDDACTRL, tmp_r);
    310 	delay(10000);
    311 
    312 	/* Enable PWDN_BRNOUT. */
    313 	REG_WR(PWR_CTRL_C, HW_POWER_CTRL_VDDA_BO_IRQ);
    314 
    315 	tmp_r = REG_RD(PWR_VDDACTRL);
    316 	tmp_r |= HW_POWER_VDDACTRL_PWDN_BRNOUT;
    317 	REG_WR(PWR_VDDACTRL, tmp_r);
    318 
    319 	return;
    320 }
    321 /*
    322  * Configure VDDIO to source power from DCDC.
    323  */
    324 void
    325 power_vddio_from_dcdc(int target, int brownout)
    326 {
    327 	uint32_t tmp_r;
    328 
    329 	/* BO_OFFSET must be within 2700mV - 3475mV */
    330 	if (brownout > 3475)
    331 		brownout = 3475;
    332 	else if (brownout < 2700)
    333 		brownout = 2700;
    334 
    335 
    336 	/* Set LINREG_OFFSET one step below TRG. */
    337 	tmp_r = REG_RD(PWR_VDDIOCTRL);
    338 	tmp_r &= ~HW_POWER_VDDIOCTRL_LINREG_OFFSET;
    339 	tmp_r |= __SHIFTIN(2, HW_POWER_VDDIOCTRL_LINREG_OFFSET);
    340 	REG_WR(PWR_VDDIOCTRL, tmp_r);
    341 	delay(10000);
    342 
    343 	/* Enable VDDIO switching converter output. */
    344 	tmp_r = REG_RD(PWR_VDDIOCTRL);
    345 	tmp_r &= ~HW_POWER_VDDIOCTRL_DISABLE_FET;
    346 	REG_WR(PWR_VDDIOCTRL, tmp_r);
    347 	delay(10000);
    348 
    349 	/* Set target voltage and brownout level. */
    350 	tmp_r = REG_RD(PWR_VDDIOCTRL);
    351 	tmp_r &= ~(HW_POWER_VDDIOCTRL_BO_OFFSET | HW_POWER_VDDIOCTRL_TRG);
    352 	tmp_r |= __SHIFTIN(((target - brownout) / 25),
    353 		HW_POWER_VDDIOCTRL_BO_OFFSET);
    354 	tmp_r |= __SHIFTIN(((target - 2800) / 25), HW_POWER_VDDIOCTRL_TRG);
    355 	REG_WR(PWR_VDDIOCTRL, tmp_r);
    356 	delay(10000);
    357 
    358 	/* Enable PWDN_BRNOUT. */
    359 	REG_WR(PWR_CTRL_C, HW_POWER_CTRL_VDDIO_BO_IRQ);
    360 
    361 	tmp_r = REG_RD(PWR_VDDIOCTRL);
    362 	tmp_r |= HW_POWER_VDDIOCTRL_PWDN_BRNOUT;
    363 	REG_WR(PWR_VDDIOCTRL, tmp_r);
    364 
    365 	return;
    366 }
    367 /*
    368  * AN3883.pdf 2.3.1.2 Setting VDDMEM Target Voltage
    369  */
    370 void
    371 power_vddmem(int target)
    372 {
    373 	uint32_t tmp_r;
    374 
    375 	/* Set target voltage. */
    376 	tmp_r = REG_RD(PWR_VDDMEMCTRL);
    377 	tmp_r &= ~(HW_POWER_VDDMEMCTRL_TRG);
    378 	tmp_r |= __SHIFTIN(((target - 1700) / 50), HW_POWER_VDDMEMCTRL_TRG);
    379 	REG_WR(PWR_VDDMEMCTRL, tmp_r);
    380 	delay(10000);
    381 
    382 	tmp_r = REG_RD(PWR_VDDMEMCTRL);
    383 	tmp_r |= (HW_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE |
    384 		HW_POWER_VDDMEMCTRL_ENABLE_ILIMIT |
    385 		HW_POWER_VDDMEMCTRL_ENABLE_LINREG);
    386 	REG_WR(PWR_VDDMEMCTRL, tmp_r);
    387 
    388 	delay(1000);
    389 
    390 	tmp_r = REG_RD(PWR_VDDMEMCTRL);
    391 	tmp_r &= ~(HW_POWER_VDDMEMCTRL_PULLDOWN_ACTIVE |
    392 		HW_POWER_VDDMEMCTRL_ENABLE_ILIMIT);
    393 	REG_WR(PWR_VDDMEMCTRL, tmp_r);
    394 
    395 	return;
    396 }
    397