xref: /OK3568_Linux_fs/u-boot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) Marvell International Ltd. and its affiliates
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <spl.h>
9*4882a593Smuzhiyun #include <asm/io.h>
10*4882a593Smuzhiyun #include <asm/arch/cpu.h>
11*4882a593Smuzhiyun #include <asm/arch/soc.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include "seq_exec.h"
14*4882a593Smuzhiyun #include "high_speed_env_spec.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #if defined(MV_DEBUG_INIT_FULL) || defined(MV_DEBUG)
19*4882a593Smuzhiyun #define DB(x)	x
20*4882a593Smuzhiyun #else
21*4882a593Smuzhiyun #define DB(x)
22*4882a593Smuzhiyun #endif
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* Array for mapping the operation (write, poll or delay) functions */
25*4882a593Smuzhiyun op_execute_func_ptr op_execute_func_arr[] = {
26*4882a593Smuzhiyun 	write_op_execute,
27*4882a593Smuzhiyun 	delay_op_execute,
28*4882a593Smuzhiyun 	poll_op_execute
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun 
write_op_execute(u32 serdes_num,struct op_params * params,u32 data_arr_idx)31*4882a593Smuzhiyun int write_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	u32 unit_base_reg, unit_offset, data, mask, reg_data, reg_addr;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	/* Getting write op params from the input parameter */
36*4882a593Smuzhiyun 	data = params->data[data_arr_idx];
37*4882a593Smuzhiyun 	mask = params->mask;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	/* an empty operation */
40*4882a593Smuzhiyun 	if (data == NO_DATA)
41*4882a593Smuzhiyun 		return MV_OK;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	/* get updated base address since it can be different between Serdes */
44*4882a593Smuzhiyun 	CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
45*4882a593Smuzhiyun 					   params->unit_offset,
46*4882a593Smuzhiyun 					   &unit_base_reg, &unit_offset));
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	/* Address calculation */
49*4882a593Smuzhiyun 	reg_addr = unit_base_reg + unit_offset * serdes_num;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #ifdef SEQ_DEBUG
52*4882a593Smuzhiyun 	printf("Write: 0x%x: 0x%x (mask 0x%x) - ", reg_addr, data, mask);
53*4882a593Smuzhiyun #endif
54*4882a593Smuzhiyun 	/* Reading old value */
55*4882a593Smuzhiyun 	reg_data = reg_read(reg_addr);
56*4882a593Smuzhiyun 	reg_data &= (~mask);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	/* Writing new data */
59*4882a593Smuzhiyun 	data &= mask;
60*4882a593Smuzhiyun 	reg_data |= data;
61*4882a593Smuzhiyun 	reg_write(reg_addr, reg_data);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #ifdef SEQ_DEBUG
64*4882a593Smuzhiyun 	printf(" - 0x%x\n", reg_data);
65*4882a593Smuzhiyun #endif
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	return MV_OK;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
delay_op_execute(u32 serdes_num,struct op_params * params,u32 data_arr_idx)70*4882a593Smuzhiyun int delay_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	u32 delay;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	/* Getting delay op params from the input parameter */
75*4882a593Smuzhiyun 	delay = params->wait_time;
76*4882a593Smuzhiyun #ifdef SEQ_DEBUG
77*4882a593Smuzhiyun 	printf("Delay: %d\n", delay);
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun 	mdelay(delay);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return MV_OK;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
poll_op_execute(u32 serdes_num,struct op_params * params,u32 data_arr_idx)84*4882a593Smuzhiyun int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	u32 unit_base_reg, unit_offset, data, mask, num_of_loops, wait_time;
87*4882a593Smuzhiyun 	u32 poll_counter = 0;
88*4882a593Smuzhiyun 	u32 reg_addr, reg_data;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	/* Getting poll op params from the input parameter */
91*4882a593Smuzhiyun 	data = params->data[data_arr_idx];
92*4882a593Smuzhiyun 	mask = params->mask;
93*4882a593Smuzhiyun 	num_of_loops = params->num_of_loops;
94*4882a593Smuzhiyun 	wait_time = params->wait_time;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	/* an empty operation */
97*4882a593Smuzhiyun 	if (data == NO_DATA)
98*4882a593Smuzhiyun 		return MV_OK;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	/* get updated base address since it can be different between Serdes */
101*4882a593Smuzhiyun 	CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
102*4882a593Smuzhiyun 					   params->unit_offset,
103*4882a593Smuzhiyun 					   &unit_base_reg, &unit_offset));
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* Address calculation */
106*4882a593Smuzhiyun 	reg_addr = unit_base_reg + unit_offset * serdes_num;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	/* Polling */
109*4882a593Smuzhiyun #ifdef SEQ_DEBUG
110*4882a593Smuzhiyun 	printf("Poll:  0x%x: 0x%x (mask 0x%x)\n", reg_addr, data, mask);
111*4882a593Smuzhiyun #endif
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	do {
114*4882a593Smuzhiyun 		reg_data = reg_read(reg_addr) & mask;
115*4882a593Smuzhiyun 		poll_counter++;
116*4882a593Smuzhiyun 		udelay(wait_time);
117*4882a593Smuzhiyun 	} while ((reg_data != data) && (poll_counter < num_of_loops));
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	if ((poll_counter >= num_of_loops) && (reg_data != data)) {
120*4882a593Smuzhiyun 		DEBUG_INIT_S("poll_op_execute: TIMEOUT\n");
121*4882a593Smuzhiyun 		return MV_TIMEOUT;
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return MV_OK;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
get_cfg_seq_op(struct op_params * params)127*4882a593Smuzhiyun enum mv_op get_cfg_seq_op(struct op_params *params)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	if (params->wait_time == 0)
130*4882a593Smuzhiyun 		return WRITE_OP;
131*4882a593Smuzhiyun 	else if (params->num_of_loops == 0)
132*4882a593Smuzhiyun 		return DELAY_OP;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return POLL_OP;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
mv_seq_exec(u32 serdes_num,u32 seq_id)137*4882a593Smuzhiyun int mv_seq_exec(u32 serdes_num, u32 seq_id)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	u32 seq_idx;
140*4882a593Smuzhiyun 	struct op_params *seq_arr;
141*4882a593Smuzhiyun 	u32 seq_size;
142*4882a593Smuzhiyun 	u32 data_arr_idx;
143*4882a593Smuzhiyun 	enum mv_op curr_op;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	DB(printf("\n### mv_seq_exec ###\n"));
146*4882a593Smuzhiyun 	DB(printf("seq id: %d\n", seq_id));
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (hws_is_serdes_active(serdes_num) != 1) {
149*4882a593Smuzhiyun 		printf("mv_seq_exec_ext:Error: SerDes lane %d is not valid\n",
150*4882a593Smuzhiyun 		       serdes_num);
151*4882a593Smuzhiyun 		return MV_BAD_PARAM;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	seq_arr = serdes_seq_db[seq_id].op_params_ptr;
155*4882a593Smuzhiyun 	seq_size = serdes_seq_db[seq_id].cfg_seq_size;
156*4882a593Smuzhiyun 	data_arr_idx = serdes_seq_db[seq_id].data_arr_idx;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	DB(printf("seq_size: %d\n", seq_size));
159*4882a593Smuzhiyun 	DB(printf("data_arr_idx: %d\n", data_arr_idx));
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	/* Executing the sequence operations */
162*4882a593Smuzhiyun 	for (seq_idx = 0; seq_idx < seq_size; seq_idx++) {
163*4882a593Smuzhiyun 		curr_op = get_cfg_seq_op(&seq_arr[seq_idx]);
164*4882a593Smuzhiyun 		op_execute_func_arr[curr_op](serdes_num, &seq_arr[seq_idx],
165*4882a593Smuzhiyun 					     data_arr_idx);
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	return MV_OK;
169*4882a593Smuzhiyun }
170