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