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