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