xref: /rk3399_ARM-atf/plat/brcm/board/stingray/driver/swreg.c (revision f29d1e0c72e6665ba4c8ab11bad83f59669ea0d9)
1*f29d1e0cSSheetal Tigadoli /*
2*f29d1e0cSSheetal Tigadoli  * Copyright (c) 2017 - 2020, Broadcom
3*f29d1e0cSSheetal Tigadoli  *
4*f29d1e0cSSheetal Tigadoli  * SPDX-License-Identifier: BSD-3-Clause
5*f29d1e0cSSheetal Tigadoli  */
6*f29d1e0cSSheetal Tigadoli 
7*f29d1e0cSSheetal Tigadoli #include <assert.h>
8*f29d1e0cSSheetal Tigadoli #include <errno.h>
9*f29d1e0cSSheetal Tigadoli #include <stdint.h>
10*f29d1e0cSSheetal Tigadoli 
11*f29d1e0cSSheetal Tigadoli #include <common/debug.h>
12*f29d1e0cSSheetal Tigadoli #include <drivers/delay_timer.h>
13*f29d1e0cSSheetal Tigadoli #include <lib/mmio.h>
14*f29d1e0cSSheetal Tigadoli 
15*f29d1e0cSSheetal Tigadoli #include <sr_utils.h>
16*f29d1e0cSSheetal Tigadoli #include <swreg.h>
17*f29d1e0cSSheetal Tigadoli 
18*f29d1e0cSSheetal Tigadoli #define MIN_VOLT                760000
19*f29d1e0cSSheetal Tigadoli #define MAX_VOLT                1060000
20*f29d1e0cSSheetal Tigadoli 
21*f29d1e0cSSheetal Tigadoli #define BSTI_WRITE              0x1
22*f29d1e0cSSheetal Tigadoli #define BSTI_READ               0x2
23*f29d1e0cSSheetal Tigadoli #define BSTI_COMMAND_TA         0x2
24*f29d1e0cSSheetal Tigadoli #define BSTI_COMMAND_DATA       0xFF
25*f29d1e0cSSheetal Tigadoli #define BSTI_CONTROL_VAL        0x81
26*f29d1e0cSSheetal Tigadoli #define BSTI_CONTROL_BUSY       0x100
27*f29d1e0cSSheetal Tigadoli #define BSTI_TOGGLE_BIT         0x2
28*f29d1e0cSSheetal Tigadoli #define BSTI_CONFI_DONE_MASK    0xFFFFFFFD
29*f29d1e0cSSheetal Tigadoli #define BSTI_REG_DATA_MASK      0xFFFF
30*f29d1e0cSSheetal Tigadoli #define BSTI_CMD(sb, op, pa, ra, ta, data) \
31*f29d1e0cSSheetal Tigadoli 	((((sb) & 0x3) << 30) | (((op) & 0x3) << 28) | \
32*f29d1e0cSSheetal Tigadoli 	(((pa) & 0x1F) << 23) | (((ra) & 0x1F) << 18) | \
33*f29d1e0cSSheetal Tigadoli 	(((ta) & 0x3) << 16) | (data))
34*f29d1e0cSSheetal Tigadoli 
35*f29d1e0cSSheetal Tigadoli #define PHY_REG0        0x0
36*f29d1e0cSSheetal Tigadoli #define PHY_REG1        0x1
37*f29d1e0cSSheetal Tigadoli #define PHY_REG4        0x4
38*f29d1e0cSSheetal Tigadoli #define PHY_REG5        0x5
39*f29d1e0cSSheetal Tigadoli #define PHY_REG6        0x6
40*f29d1e0cSSheetal Tigadoli #define PHY_REG7        0x7
41*f29d1e0cSSheetal Tigadoli #define PHY_REGC        0xc
42*f29d1e0cSSheetal Tigadoli 
43*f29d1e0cSSheetal Tigadoli #define IHOST_VDDC_DATA 0x560
44*f29d1e0cSSheetal Tigadoli #define DDR_CORE_DATA   0x2560
45*f29d1e0cSSheetal Tigadoli #define UPDATE_POS_EDGE(data, set)    ((data) | ((set) << 1))
46*f29d1e0cSSheetal Tigadoli 
47*f29d1e0cSSheetal Tigadoli /*
48*f29d1e0cSSheetal Tigadoli  * Formula for SR A2 reworked board:
49*f29d1e0cSSheetal Tigadoli  * step = ((vol/(1.4117 * 0.98)) - 500000)/3125
50*f29d1e0cSSheetal Tigadoli  * where,
51*f29d1e0cSSheetal Tigadoli  *      vol    - input voltage
52*f29d1e0cSSheetal Tigadoli  *      500000 - Reference voltage
53*f29d1e0cSSheetal Tigadoli  *      3125   - one step value
54*f29d1e0cSSheetal Tigadoli  */
55*f29d1e0cSSheetal Tigadoli #define A2_VOL_REF         500000
56*f29d1e0cSSheetal Tigadoli #define ONE_STEP_VALUE  3125
57*f29d1e0cSSheetal Tigadoli #define VOL_DIV(vol)    (((vol*10000ull)/(14117*98ull)) * 100ull)
58*f29d1e0cSSheetal Tigadoli #define STEP_VALUE(vol) \
59*f29d1e0cSSheetal Tigadoli 	((((((VOL_DIV(vol)) - A2_VOL_REF) / ONE_STEP_VALUE) & 0xFF) << 8) | 4)
60*f29d1e0cSSheetal Tigadoli 
61*f29d1e0cSSheetal Tigadoli #define B0_VOL_REF         ((500000/100)*98)
62*f29d1e0cSSheetal Tigadoli #define B0_ONE_STEP_VALUE  3125
63*f29d1e0cSSheetal Tigadoli /*
64*f29d1e0cSSheetal Tigadoli  * Formula for SR B0 chip for IHOST12/03 and VDDC_CORE
65*f29d1e0cSSheetal Tigadoli  * step = ((vol/1.56) - (500000 * 0.98))/3125
66*f29d1e0cSSheetal Tigadoli  * where,
67*f29d1e0cSSheetal Tigadoli  *      vol    - input voltage
68*f29d1e0cSSheetal Tigadoli  *      500000 - Reference voltage
69*f29d1e0cSSheetal Tigadoli  *      3125   - one step value
70*f29d1e0cSSheetal Tigadoli  */
71*f29d1e0cSSheetal Tigadoli #define B0_VOL_DIV(vol)    (((vol)*100ull)/156)
72*f29d1e0cSSheetal Tigadoli #define B0_STEP_VALUE(vol) \
73*f29d1e0cSSheetal Tigadoli 	((((((B0_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
74*f29d1e0cSSheetal Tigadoli 		& 0xFF) << 8) | 4)
75*f29d1e0cSSheetal Tigadoli 
76*f29d1e0cSSheetal Tigadoli /*
77*f29d1e0cSSheetal Tigadoli  * Formula for SR B0 chip for DDR-CORE
78*f29d1e0cSSheetal Tigadoli  * step = ((vol/1) - (500000 * 0.98))/3125
79*f29d1e0cSSheetal Tigadoli  * where,
80*f29d1e0cSSheetal Tigadoli  *      vol    - input voltage
81*f29d1e0cSSheetal Tigadoli  *      500000 - Reference voltage
82*f29d1e0cSSheetal Tigadoli  *      3125   - one step value
83*f29d1e0cSSheetal Tigadoli  */
84*f29d1e0cSSheetal Tigadoli #define B0_DDR_VDDC_VOL_DIV(vol)    ((vol)/1)
85*f29d1e0cSSheetal Tigadoli #define B0_DDR_VDDC_STEP_VALUE(vol) \
86*f29d1e0cSSheetal Tigadoli 	((((((B0_DDR_VDDC_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
87*f29d1e0cSSheetal Tigadoli 		& 0xFF) << 8) | 4)
88*f29d1e0cSSheetal Tigadoli 
89*f29d1e0cSSheetal Tigadoli #define MAX_SWREG_CNT       8
90*f29d1e0cSSheetal Tigadoli #define MAX_ADDR_PER_SWREG  16
91*f29d1e0cSSheetal Tigadoli #define MAX_REG_ADDR        0xF
92*f29d1e0cSSheetal Tigadoli #define MIN_REG_ADDR        0x0
93*f29d1e0cSSheetal Tigadoli 
94*f29d1e0cSSheetal Tigadoli static const char *sw_reg_name[MAX_SWREG_CNT] = {
95*f29d1e0cSSheetal Tigadoli 	"DDR_VDDC",
96*f29d1e0cSSheetal Tigadoli 	"IHOST03",
97*f29d1e0cSSheetal Tigadoli 	"IHOST12",
98*f29d1e0cSSheetal Tigadoli 	"IHOST_ARRAY",
99*f29d1e0cSSheetal Tigadoli 	"DDRIO_SLAVE",
100*f29d1e0cSSheetal Tigadoli 	"VDDC_CORE",
101*f29d1e0cSSheetal Tigadoli 	"VDDC1",
102*f29d1e0cSSheetal Tigadoli 	"DDRIO_MASTER"
103*f29d1e0cSSheetal Tigadoli };
104*f29d1e0cSSheetal Tigadoli 
105*f29d1e0cSSheetal Tigadoli /* firmware values for all SWREG for 3.3V input operation */
106*f29d1e0cSSheetal Tigadoli static const uint16_t swreg_fm_data_bx[MAX_SWREG_CNT][MAX_ADDR_PER_SWREG] = {
107*f29d1e0cSSheetal Tigadoli 	/* DDR logic: Power Domains independent of 12v or 3p3v */
108*f29d1e0cSSheetal Tigadoli 	{0x25E0, 0x2D54, 0x0EC6, 0x01EC, 0x28BB, 0x1144, 0x0200, 0x69C0,
109*f29d1e0cSSheetal Tigadoli 	 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x820C, 0x0003, 0x0001, 0x0000},
110*f29d1e0cSSheetal Tigadoli 
111*f29d1e0cSSheetal Tigadoli 	/* ihost03, 3p3V */
112*f29d1e0cSSheetal Tigadoli 	{0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
113*f29d1e0cSSheetal Tigadoli 	 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
114*f29d1e0cSSheetal Tigadoli 
115*f29d1e0cSSheetal Tigadoli 	/* ihost12 3p3v */
116*f29d1e0cSSheetal Tigadoli 	{0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
117*f29d1e0cSSheetal Tigadoli 	 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
118*f29d1e0cSSheetal Tigadoli 
119*f29d1e0cSSheetal Tigadoli 	/* ihost array */
120*f29d1e0cSSheetal Tigadoli 	{0x25E0, 0x2D94, 0x0EC6, 0x01EC, 0x2ABB, 0x1144, 0x0340, 0x69C0,
121*f29d1e0cSSheetal Tigadoli 	 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x860C, 0x0003, 0x0001, 0x0000},
122*f29d1e0cSSheetal Tigadoli 
123*f29d1e0cSSheetal Tigadoli 	/* ddr io slave : 3p3v */
124*f29d1e0cSSheetal Tigadoli 	{0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
125*f29d1e0cSSheetal Tigadoli 	 0x003F, 0x0FFF, 0x10D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
126*f29d1e0cSSheetal Tigadoli 
127*f29d1e0cSSheetal Tigadoli 	/* core master 3p3v */
128*f29d1e0cSSheetal Tigadoli 	{0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
129*f29d1e0cSSheetal Tigadoli 	 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
130*f29d1e0cSSheetal Tigadoli 
131*f29d1e0cSSheetal Tigadoli 	/* core slave 3p3v */
132*f29d1e0cSSheetal Tigadoli 	{0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
133*f29d1e0cSSheetal Tigadoli 	 0x003F, 0x0FFF, 0x10D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
134*f29d1e0cSSheetal Tigadoli 
135*f29d1e0cSSheetal Tigadoli 	/* ddr io master : 3p3v */
136*f29d1e0cSSheetal Tigadoli 	{0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
137*f29d1e0cSSheetal Tigadoli 	 0x003F, 0x0FFF, 0x90D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
138*f29d1e0cSSheetal Tigadoli };
139*f29d1e0cSSheetal Tigadoli 
140*f29d1e0cSSheetal Tigadoli #define FM_DATA swreg_fm_data_bx
141*f29d1e0cSSheetal Tigadoli 
142*f29d1e0cSSheetal Tigadoli static int swreg_poll(void)
143*f29d1e0cSSheetal Tigadoli {
144*f29d1e0cSSheetal Tigadoli 	uint32_t data;
145*f29d1e0cSSheetal Tigadoli 	int retry = 100;
146*f29d1e0cSSheetal Tigadoli 
147*f29d1e0cSSheetal Tigadoli 	do {
148*f29d1e0cSSheetal Tigadoli 		data = mmio_read_32(BSTI_CONTROL_OFFSET);
149*f29d1e0cSSheetal Tigadoli 		if ((data & BSTI_CONTROL_BUSY) != BSTI_CONTROL_BUSY)
150*f29d1e0cSSheetal Tigadoli 			return 0;
151*f29d1e0cSSheetal Tigadoli 		retry--;
152*f29d1e0cSSheetal Tigadoli 		udelay(1);
153*f29d1e0cSSheetal Tigadoli 	} while (retry > 0);
154*f29d1e0cSSheetal Tigadoli 
155*f29d1e0cSSheetal Tigadoli 	return -ETIMEDOUT;
156*f29d1e0cSSheetal Tigadoli }
157*f29d1e0cSSheetal Tigadoli 
158*f29d1e0cSSheetal Tigadoli static int write_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t data)
159*f29d1e0cSSheetal Tigadoli {
160*f29d1e0cSSheetal Tigadoli 	uint32_t cmd;
161*f29d1e0cSSheetal Tigadoli 	int ret;
162*f29d1e0cSSheetal Tigadoli 
163*f29d1e0cSSheetal Tigadoli 	cmd = BSTI_CMD(0x1, BSTI_WRITE, reg_id, addr, BSTI_COMMAND_TA, data);
164*f29d1e0cSSheetal Tigadoli 	mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
165*f29d1e0cSSheetal Tigadoli 	mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
166*f29d1e0cSSheetal Tigadoli 	ret = swreg_poll();
167*f29d1e0cSSheetal Tigadoli 	if (ret) {
168*f29d1e0cSSheetal Tigadoli 		ERROR("Failed to write swreg %s addr 0x%x\n",
169*f29d1e0cSSheetal Tigadoli 			sw_reg_name[reg_id-1], addr);
170*f29d1e0cSSheetal Tigadoli 		return ret;
171*f29d1e0cSSheetal Tigadoli 	}
172*f29d1e0cSSheetal Tigadoli 	return ret;
173*f29d1e0cSSheetal Tigadoli }
174*f29d1e0cSSheetal Tigadoli 
175*f29d1e0cSSheetal Tigadoli static int read_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t *data)
176*f29d1e0cSSheetal Tigadoli {
177*f29d1e0cSSheetal Tigadoli 	uint32_t cmd;
178*f29d1e0cSSheetal Tigadoli 	int ret;
179*f29d1e0cSSheetal Tigadoli 
180*f29d1e0cSSheetal Tigadoli 	cmd = BSTI_CMD(0x1, BSTI_READ, reg_id, addr, BSTI_COMMAND_TA, PHY_REG0);
181*f29d1e0cSSheetal Tigadoli 	mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
182*f29d1e0cSSheetal Tigadoli 	mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
183*f29d1e0cSSheetal Tigadoli 	ret = swreg_poll();
184*f29d1e0cSSheetal Tigadoli 	if (ret) {
185*f29d1e0cSSheetal Tigadoli 		ERROR("Failed to read swreg %s addr 0x%x\n",
186*f29d1e0cSSheetal Tigadoli 			sw_reg_name[reg_id-1], addr);
187*f29d1e0cSSheetal Tigadoli 		return ret;
188*f29d1e0cSSheetal Tigadoli 	}
189*f29d1e0cSSheetal Tigadoli 
190*f29d1e0cSSheetal Tigadoli 	*data = mmio_read_32(BSTI_COMMAND_OFFSET);
191*f29d1e0cSSheetal Tigadoli 	*data &= BSTI_REG_DATA_MASK;
192*f29d1e0cSSheetal Tigadoli 	return ret;
193*f29d1e0cSSheetal Tigadoli }
194*f29d1e0cSSheetal Tigadoli 
195*f29d1e0cSSheetal Tigadoli static int swreg_config_done(enum sw_reg reg_id)
196*f29d1e0cSSheetal Tigadoli {
197*f29d1e0cSSheetal Tigadoli 	uint32_t read_data;
198*f29d1e0cSSheetal Tigadoli 	int ret;
199*f29d1e0cSSheetal Tigadoli 
200*f29d1e0cSSheetal Tigadoli 	ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
201*f29d1e0cSSheetal Tigadoli 	if (ret)
202*f29d1e0cSSheetal Tigadoli 		return ret;
203*f29d1e0cSSheetal Tigadoli 
204*f29d1e0cSSheetal Tigadoli 	read_data &= BSTI_CONFI_DONE_MASK;
205*f29d1e0cSSheetal Tigadoli 	read_data |= BSTI_TOGGLE_BIT;
206*f29d1e0cSSheetal Tigadoli 	ret = write_swreg_config(reg_id, PHY_REG0, read_data);
207*f29d1e0cSSheetal Tigadoli 	if (ret)
208*f29d1e0cSSheetal Tigadoli 		return ret;
209*f29d1e0cSSheetal Tigadoli 
210*f29d1e0cSSheetal Tigadoli 	ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
211*f29d1e0cSSheetal Tigadoli 	if (ret)
212*f29d1e0cSSheetal Tigadoli 		return ret;
213*f29d1e0cSSheetal Tigadoli 
214*f29d1e0cSSheetal Tigadoli 	read_data &= BSTI_CONFI_DONE_MASK;
215*f29d1e0cSSheetal Tigadoli 	ret = write_swreg_config(reg_id, PHY_REG0, read_data);
216*f29d1e0cSSheetal Tigadoli 	if (ret)
217*f29d1e0cSSheetal Tigadoli 		return ret;
218*f29d1e0cSSheetal Tigadoli 
219*f29d1e0cSSheetal Tigadoli 	return ret;
220*f29d1e0cSSheetal Tigadoli }
221*f29d1e0cSSheetal Tigadoli 
222*f29d1e0cSSheetal Tigadoli #ifdef DUMP_SWREG
223*f29d1e0cSSheetal Tigadoli static void dump_swreg_firmware(void)
224*f29d1e0cSSheetal Tigadoli {
225*f29d1e0cSSheetal Tigadoli 	enum sw_reg reg_id;
226*f29d1e0cSSheetal Tigadoli 	uint32_t data;
227*f29d1e0cSSheetal Tigadoli 	int addr;
228*f29d1e0cSSheetal Tigadoli 	int ret;
229*f29d1e0cSSheetal Tigadoli 
230*f29d1e0cSSheetal Tigadoli 	for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
231*f29d1e0cSSheetal Tigadoli 		INFO("SWREG: %s\n", sw_reg_name[reg_id - 1]);
232*f29d1e0cSSheetal Tigadoli 		for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
233*f29d1e0cSSheetal Tigadoli 			ret = read_swreg_config(reg_id, addr, &data);
234*f29d1e0cSSheetal Tigadoli 			if (ret)
235*f29d1e0cSSheetal Tigadoli 				ERROR("Failed to read offset %d\n", addr);
236*f29d1e0cSSheetal Tigadoli 			INFO("\t0x%x: 0x%04x\n", addr, data);
237*f29d1e0cSSheetal Tigadoli 		}
238*f29d1e0cSSheetal Tigadoli 	}
239*f29d1e0cSSheetal Tigadoli }
240*f29d1e0cSSheetal Tigadoli #endif
241*f29d1e0cSSheetal Tigadoli 
242*f29d1e0cSSheetal Tigadoli int set_swreg(enum sw_reg reg_id, uint32_t micro_volts)
243*f29d1e0cSSheetal Tigadoli {
244*f29d1e0cSSheetal Tigadoli 	uint32_t step, programmed_step;
245*f29d1e0cSSheetal Tigadoli 	uint32_t data = IHOST_VDDC_DATA;
246*f29d1e0cSSheetal Tigadoli 	int ret;
247*f29d1e0cSSheetal Tigadoli 
248*f29d1e0cSSheetal Tigadoli 	if ((micro_volts > MAX_VOLT) || (micro_volts < MIN_VOLT)) {
249*f29d1e0cSSheetal Tigadoli 		ERROR("input voltage out-of-range\n");
250*f29d1e0cSSheetal Tigadoli 		ret = -EINVAL;
251*f29d1e0cSSheetal Tigadoli 		goto failed;
252*f29d1e0cSSheetal Tigadoli 	}
253*f29d1e0cSSheetal Tigadoli 
254*f29d1e0cSSheetal Tigadoli 	ret = read_swreg_config(reg_id, PHY_REGC, &programmed_step);
255*f29d1e0cSSheetal Tigadoli 	if (ret)
256*f29d1e0cSSheetal Tigadoli 		goto failed;
257*f29d1e0cSSheetal Tigadoli 
258*f29d1e0cSSheetal Tigadoli 	if (reg_id == DDR_VDDC)
259*f29d1e0cSSheetal Tigadoli 		step = B0_DDR_VDDC_STEP_VALUE(micro_volts);
260*f29d1e0cSSheetal Tigadoli 	else
261*f29d1e0cSSheetal Tigadoli 		step = B0_STEP_VALUE(micro_volts);
262*f29d1e0cSSheetal Tigadoli 
263*f29d1e0cSSheetal Tigadoli 	if ((step >> 8) != (programmed_step >> 8)) {
264*f29d1e0cSSheetal Tigadoli 		ret = write_swreg_config(reg_id, PHY_REGC, step);
265*f29d1e0cSSheetal Tigadoli 		if (ret)
266*f29d1e0cSSheetal Tigadoli 			goto failed;
267*f29d1e0cSSheetal Tigadoli 
268*f29d1e0cSSheetal Tigadoli 		if (reg_id == DDR_VDDC)
269*f29d1e0cSSheetal Tigadoli 			data = DDR_CORE_DATA;
270*f29d1e0cSSheetal Tigadoli 
271*f29d1e0cSSheetal Tigadoli 		ret = write_swreg_config(reg_id, PHY_REG0,
272*f29d1e0cSSheetal Tigadoli 					UPDATE_POS_EDGE(data, 1));
273*f29d1e0cSSheetal Tigadoli 		if (ret)
274*f29d1e0cSSheetal Tigadoli 			goto failed;
275*f29d1e0cSSheetal Tigadoli 
276*f29d1e0cSSheetal Tigadoli 		ret = write_swreg_config(reg_id, PHY_REG0,
277*f29d1e0cSSheetal Tigadoli 					UPDATE_POS_EDGE(data, 0));
278*f29d1e0cSSheetal Tigadoli 		if (ret)
279*f29d1e0cSSheetal Tigadoli 			goto failed;
280*f29d1e0cSSheetal Tigadoli 	}
281*f29d1e0cSSheetal Tigadoli 
282*f29d1e0cSSheetal Tigadoli 	INFO("%s voltage updated to %duV\n", sw_reg_name[reg_id-1],
283*f29d1e0cSSheetal Tigadoli 		micro_volts);
284*f29d1e0cSSheetal Tigadoli 	return ret;
285*f29d1e0cSSheetal Tigadoli 
286*f29d1e0cSSheetal Tigadoli failed:
287*f29d1e0cSSheetal Tigadoli 	/*
288*f29d1e0cSSheetal Tigadoli 	 * Stop booting if voltages are not set
289*f29d1e0cSSheetal Tigadoli 	 * correctly. Booting will fail at random point
290*f29d1e0cSSheetal Tigadoli 	 * if we continue with wrong voltage settings.
291*f29d1e0cSSheetal Tigadoli 	 */
292*f29d1e0cSSheetal Tigadoli 	ERROR("Failed to set %s voltage to %duV\n", sw_reg_name[reg_id-1],
293*f29d1e0cSSheetal Tigadoli 		micro_volts);
294*f29d1e0cSSheetal Tigadoli 	assert(0);
295*f29d1e0cSSheetal Tigadoli 
296*f29d1e0cSSheetal Tigadoli 	return ret;
297*f29d1e0cSSheetal Tigadoli }
298*f29d1e0cSSheetal Tigadoli 
299*f29d1e0cSSheetal Tigadoli /* Update SWREG firmware for all power doman for A2 chip */
300*f29d1e0cSSheetal Tigadoli int swreg_firmware_update(void)
301*f29d1e0cSSheetal Tigadoli {
302*f29d1e0cSSheetal Tigadoli 	enum sw_reg reg_id;
303*f29d1e0cSSheetal Tigadoli 	uint32_t data;
304*f29d1e0cSSheetal Tigadoli 	int addr;
305*f29d1e0cSSheetal Tigadoli 	int ret;
306*f29d1e0cSSheetal Tigadoli 
307*f29d1e0cSSheetal Tigadoli 	/* write firmware values */
308*f29d1e0cSSheetal Tigadoli 	for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
309*f29d1e0cSSheetal Tigadoli 		/* write higher location first */
310*f29d1e0cSSheetal Tigadoli 		for (addr = MAX_REG_ADDR; addr >= MIN_REG_ADDR; addr--) {
311*f29d1e0cSSheetal Tigadoli 			ret = write_swreg_config(reg_id, addr,
312*f29d1e0cSSheetal Tigadoli 						 FM_DATA[reg_id - 1][addr]);
313*f29d1e0cSSheetal Tigadoli 			if (ret)
314*f29d1e0cSSheetal Tigadoli 				goto exit;
315*f29d1e0cSSheetal Tigadoli 		}
316*f29d1e0cSSheetal Tigadoli 	}
317*f29d1e0cSSheetal Tigadoli 
318*f29d1e0cSSheetal Tigadoli 	/* trigger SWREG firmware update */
319*f29d1e0cSSheetal Tigadoli 	for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
320*f29d1e0cSSheetal Tigadoli 		/*
321*f29d1e0cSSheetal Tigadoli 		 * Slave regulator doesn't have to be updated,
322*f29d1e0cSSheetal Tigadoli 		 * Updating Master is enough
323*f29d1e0cSSheetal Tigadoli 		 */
324*f29d1e0cSSheetal Tigadoli 		if ((reg_id == DDRIO_SLAVE) || (reg_id == VDDC1))
325*f29d1e0cSSheetal Tigadoli 			continue;
326*f29d1e0cSSheetal Tigadoli 
327*f29d1e0cSSheetal Tigadoli 		ret = swreg_config_done(reg_id);
328*f29d1e0cSSheetal Tigadoli 		if (ret) {
329*f29d1e0cSSheetal Tigadoli 			ERROR("Failed to trigger SWREG firmware update for %s\n"
330*f29d1e0cSSheetal Tigadoli 				, sw_reg_name[reg_id-1]);
331*f29d1e0cSSheetal Tigadoli 			return ret;
332*f29d1e0cSSheetal Tigadoli 		}
333*f29d1e0cSSheetal Tigadoli 	}
334*f29d1e0cSSheetal Tigadoli 
335*f29d1e0cSSheetal Tigadoli 	for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
336*f29d1e0cSSheetal Tigadoli 		/*
337*f29d1e0cSSheetal Tigadoli 		 * IHOST_ARRAY will be used on some boards like STRATUS and
338*f29d1e0cSSheetal Tigadoli 		 * there will not be any issue even if it is updated on other
339*f29d1e0cSSheetal Tigadoli 		 * boards where it is not used.
340*f29d1e0cSSheetal Tigadoli 		 */
341*f29d1e0cSSheetal Tigadoli 		if (reg_id == IHOST_ARRAY)
342*f29d1e0cSSheetal Tigadoli 			continue;
343*f29d1e0cSSheetal Tigadoli 
344*f29d1e0cSSheetal Tigadoli 		for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
345*f29d1e0cSSheetal Tigadoli 			ret = read_swreg_config(reg_id, addr, &data);
346*f29d1e0cSSheetal Tigadoli 			if (ret || (!ret &&
347*f29d1e0cSSheetal Tigadoli 				(data != FM_DATA[reg_id - 1][addr]))) {
348*f29d1e0cSSheetal Tigadoli 				ERROR("swreg fm update failed: %s at off %d\n",
349*f29d1e0cSSheetal Tigadoli 					sw_reg_name[reg_id - 1], addr);
350*f29d1e0cSSheetal Tigadoli 				ERROR("Read val: 0x%x, expected val: 0x%x\n",
351*f29d1e0cSSheetal Tigadoli 					data, FM_DATA[reg_id - 1][addr]);
352*f29d1e0cSSheetal Tigadoli 				return -1;
353*f29d1e0cSSheetal Tigadoli 			}
354*f29d1e0cSSheetal Tigadoli 		}
355*f29d1e0cSSheetal Tigadoli 	}
356*f29d1e0cSSheetal Tigadoli 
357*f29d1e0cSSheetal Tigadoli 	INFO("Updated SWREG firmware\n");
358*f29d1e0cSSheetal Tigadoli 
359*f29d1e0cSSheetal Tigadoli #ifdef DUMP_SWREG
360*f29d1e0cSSheetal Tigadoli 	dump_swreg_firmware();
361*f29d1e0cSSheetal Tigadoli #endif
362*f29d1e0cSSheetal Tigadoli 	return ret;
363*f29d1e0cSSheetal Tigadoli 
364*f29d1e0cSSheetal Tigadoli exit:
365*f29d1e0cSSheetal Tigadoli 	/*
366*f29d1e0cSSheetal Tigadoli 	 * Stop booting if swreg firmware update fails.
367*f29d1e0cSSheetal Tigadoli 	 * Booting will fail at random point if we
368*f29d1e0cSSheetal Tigadoli 	 * continue with wrong voltage settings.
369*f29d1e0cSSheetal Tigadoli 	 */
370*f29d1e0cSSheetal Tigadoli 	ERROR("Failed to update firmware for %s SWREG\n",
371*f29d1e0cSSheetal Tigadoli 		sw_reg_name[reg_id-1]);
372*f29d1e0cSSheetal Tigadoli 	assert(0);
373*f29d1e0cSSheetal Tigadoli 
374*f29d1e0cSSheetal Tigadoli 	return ret;
375*f29d1e0cSSheetal Tigadoli }
376