From: Viktor Barna <viktor.barna@xxxxxxxxxx> (Part of the split. Please, take a look at the cover letter for more details). Signed-off-by: Viktor Barna <viktor.barna@xxxxxxxxxx> --- drivers/net/wireless/celeno/cl8k/rfic.c | 232 ++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 drivers/net/wireless/celeno/cl8k/rfic.c diff --git a/drivers/net/wireless/celeno/cl8k/rfic.c b/drivers/net/wireless/celeno/cl8k/rfic.c new file mode 100644 index 000000000000..5a3a595694b5 --- /dev/null +++ b/drivers/net/wireless/celeno/cl8k/rfic.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* Copyright(c) 2019-2022, Celeno Communications Ltd. */ + +#include <linux/namei.h> + +#include "reg/reg_defs.h" +#include "phy.h" +#include "utils.h" +#include "rfic.h" + +#define PHY_DEV_NON_PHYSICAL 0x0 +#define MAX_LOOPS 15 +#define READ_REQ 1 +#define WRITE_REQ 0 + +int cl_spi_read(struct cl_hw *cl_hw, u8 page, u8 addr, u8 *val) +{ + struct mm_spi_read_cfm *cfm; + int ret = cl_msg_tx_spi_read(cl_hw, page, addr); + + if (ret) + goto out; + + cfm = (struct mm_spi_read_cfm *)(cl_hw->msg_cfm_params[MM_SPI_READ_CFM]); + if (!cfm) { + ret = -ENOMSG; + goto out; + } + + if (cfm->status == 0) { + *val = cfm->val; + } else { + cl_dbg_err(cl_hw, "SPI read failed\n"); + *val = 0; + } + + cl_msg_tx_free_cfm_params(cl_hw, MM_SPI_READ_CFM); + return 0; + +out: + *val = 0; + return ret; +} + +static int _cl_spi_driver_read(struct cl_hw *cl_hw, u8 more, u8 addr, u8 *val) +{ + u8 prescaler = 4; + int loops = MAX_LOOPS; + + riu_rc_sw_ctrl_pack(cl_hw, 1, more, 0, 0, 1, 1, 1, 1, prescaler, READ_REQ, addr, 0xFF); + while (riu_rc_sw_ctrl_start_done_getf(cl_hw) && --loops) + ; + + if (!loops) { + cl_dbg_verbose(cl_hw, "Read error - addr [0x%02x]\n", addr); + return -EBADE; + } + + *val = riu_rc_sw_ctrl_data_getf(cl_hw); + + hwreg_pr(cl_hw, "more=%d, addr=0x%x, *val=0x%x\n", more, addr, *val); + + return 0; +} + +static int _cl_spi_driver_write(struct cl_hw *cl_hw, u8 more, u8 addr, u8 val) +{ + u8 prescaler = 4; + int loops = MAX_LOOPS; + + hwreg_pr(cl_hw, "more=%d, addr=0x%x, val=0x%x\n", more, addr, val); + + riu_rc_sw_ctrl_pack(cl_hw, 1, more, 0, 0, 1, 1, 1, 1, prescaler, WRITE_REQ, addr, val); + + while (riu_rc_sw_ctrl_start_done_getf(cl_hw) && --loops) + ; + + if (!loops) { + cl_dbg_verbose(cl_hw, "Write error - addr [0x%02x] val [0x%02x]\n", addr, val); + return -EBADE; + } + + return 0; +} + +int cl_spi_driver_read_byte(struct cl_hw *cl_hw, u8 page, u8 addr, u8 *val) +{ + /* cl_spi_driver_read_byte should only be used when mac fw not loaded, + * else use cl_spi_read + */ + int ret = 0; + + spin_lock_bh(&cl_hw->chip->isr_lock); + + ret = _cl_spi_driver_write(cl_hw, 1, 0x03, page); + if (ret) + goto read_exit; + + ret = _cl_spi_driver_read(cl_hw, 0, addr, val); + if (ret) + goto read_exit; + +read_exit: + spin_unlock_bh(&cl_hw->chip->isr_lock); + + return ret; +} + +static u8 cl_rfic_str_to_cmd(struct cl_hw *cl_hw, char *str) +{ + if (!strcmp(str, "DONE")) + return OVERWRITE_DONE; + else if (!strcmp(str, "SPI_R")) + return SPI_RD_CMD; + else if (!strcmp(str, "SPI_W")) + return SPI_WR_CMD; + else if (!strcmp(str, "GCU_W")) + return GCU_WR_CMD; + else if (!strcmp(str, "RIU_W")) + return RIU_WR_CMD; + else if (!strcmp(str, "GEN_W")) + return GEN_WR_CMD; + else if (!strcmp(str, "DELAY")) + return UDELAY_CMD; + + cl_dbg_err(cl_hw, "unknown command %s\n", str); + return OVERWRITE_DONE; +} + +static void cl_parse_rf_command(struct cl_hw *cl_hw, char *str, + struct cl_rf_reg_overwrite_info *info) +{ + int i = 0; + char *ptr = NULL; + u32 res = 0; + + while ((ptr = strsep(&str, " ")) && (*ptr != '\n')) { + if (i == 0) { + info->cmd = cl_rfic_str_to_cmd(cl_hw, ptr); + } else { + if (kstrtou32(ptr, 16, &res) != 0) { + pr_err("%s: invalid data - %s\n", __func__, ptr); + return; + } + + info->data[i - 1] = cpu_to_le32(res); + res = 0; + } + i++; + } +} + +#define RF_CMD_MAX_LEN 64 + +static void cl_parse_rf_commands_from_buf(struct cl_hw *cl_hw, char *buf, loff_t size, + struct cl_rf_reg_overwrite_info *info) +{ + int i = 0; + char *line = buf; + char str[RF_CMD_MAX_LEN]; + char *end; + int line_length = 0; + + while (line && (line != (buf + size))) { + if ((*line == '#') || (*line == '\n')) { + /* Skip comment or blank line */ + line = strstr(line, "\n") + 1; + } else if (*line) { + end = strstr(line, "\n") + 1; + line_length = end - line; + + if (line_length >= RF_CMD_MAX_LEN) { + cl_dbg_err(cl_hw, "Command too long (%u)\n", line_length); + return; + } + + snprintf(str, line_length, "%s", line); + cl_parse_rf_command(cl_hw, str, &info[i++]); + line += line_length; + } + } +} + +int cl_rfic_read_overwrite_file(struct cl_hw *cl_hw, struct cl_rf_reg_overwrite_info *info, + bool init) +{ + char *buf = NULL; + size_t size = 0; + char filename[CL_FILENAME_MAX] = {0}; + char path_name[CL_PATH_MAX] = {0}; + struct path path; + + if (init) + snprintf(filename, sizeof(filename), "rf_init_overwrite.txt"); + else + snprintf(filename, sizeof(filename), "rf_tcv%d_overwrite.txt", cl_hw->tcv_idx); + + snprintf(path_name, sizeof(path_name), "/lib/firmware/cl8k/%s", filename); + if (kern_path(path_name, LOOKUP_FOLLOW, &path) < 0) + return 0; + + size = cl_file_open_and_read(cl_hw->chip, filename, &buf); + + if (!buf) + return 0; + + cl_dbg_trace(cl_hw, "parsing %s !!!\n", filename); + cl_parse_rf_commands_from_buf(cl_hw, buf, size, info); + kfree(buf); + return 0; +} + +static u8 cl_rfic_version(struct cl_hw *cl_hw) +{ + u8 value = 0xff; + int ret = cl_spi_driver_read_byte(cl_hw, 0, 0, &value); + + if (ret < 0) + cl_dbg_err(cl_hw, "%s: spi read failed", __func__); + + return value; +} + +void cl_chip_set_rfic_version(struct cl_hw *cl_hw) +{ /* Read version only on a physical phy */ + if (cl_hw->chip->conf->ci_phy_dev == PHY_DEV_ATHOS || + cl_hw->chip->conf->ci_phy_dev == PHY_DEV_OLYMPUS) { + cl_hw->chip->rfic_version = cl_rfic_version(cl_hw); + } else { + cl_hw->chip->rfic_version = PHY_DEV_NON_PHYSICAL; + } +} -- 2.36.1