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