Home | History | Annotate | Download | only in a38x
      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