uboot/arch/arm/mach-mvebu/serdes/a38x/seq_exec.c
<<
>>
Prefs
   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#include <linux/delay.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 */
  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}
 170