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