1 /* 2 * Copyright (C) Marvell International Ltd. and its affiliates 3 * 4 * SPDX-License-Identifier: GPL-2.0 5 */ 6 7 #include <common.h> 8 #include <spl.h> 9 #include <asm/io.h> 10 #include <asm/arch/cpu.h> 11 #include <asm/arch/soc.h> 12 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 */ 25 op_execute_func_ptr op_execute_func_arr[] = { 26 write_op_execute, 27 delay_op_execute, 28 poll_op_execute 29 }; 30 31 int 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 70 int 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 84 int 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 127 enum 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 137 int 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 } 170