Path: blob/master/drivers/net/wireless/realtek/rtw88/efuse.c
25924 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/* Copyright(c) 2018-2019 Realtek Corporation2*/34#include <linux/iopoll.h>56#include "main.h"7#include "efuse.h"8#include "reg.h"9#include "debug.h"1011#define RTW_EFUSE_BANK_WIFI 0x01213static void switch_efuse_bank(struct rtw_dev *rtwdev)14{15rtw_write32_mask(rtwdev, REG_LDO_EFUSE_CTRL, BIT_MASK_EFUSE_BANK_SEL,16RTW_EFUSE_BANK_WIFI);17}1819#define invalid_efuse_header(hdr1, hdr2) \20((hdr1) == 0xff || (((hdr1) & 0x1f) == 0xf && (hdr2) == 0xff))21#define invalid_efuse_content(word_en, i) \22(((word_en) & BIT(i)) != 0x0)23#define get_efuse_blk_idx_2_byte(hdr1, hdr2) \24((((hdr2) & 0xf0) >> 1) | (((hdr1) >> 5) & 0x07))25#define get_efuse_blk_idx_1_byte(hdr1) \26(((hdr1) & 0xf0) >> 4)27#define block_idx_to_logical_idx(blk_idx, i) \28(((blk_idx) << 3) + ((i) << 1))2930/* efuse header format31*32* | 7 5 4 0 | 7 4 3 0 | 15 8 7 0 |33* block[2:0] 0 1111 block[6:3] word_en[3:0] byte0 byte134* | header 1 (optional) | header 2 | word N |35*36* word_en: 4 bits each word. 0 -> write; 1 -> not write37* N: 1~4, depends on word_en38*/39static int rtw_dump_logical_efuse_map(struct rtw_dev *rtwdev, u8 *phy_map,40u8 *log_map)41{42u32 physical_size = rtwdev->efuse.physical_size;43u32 protect_size = rtwdev->efuse.protect_size;44u32 logical_size = rtwdev->efuse.logical_size;45u32 phy_idx, log_idx;46u8 hdr1, hdr2;47u8 blk_idx;48u8 word_en;49int i;5051for (phy_idx = 0; phy_idx < physical_size - protect_size;) {52hdr1 = phy_map[phy_idx];53hdr2 = phy_map[phy_idx + 1];54if (invalid_efuse_header(hdr1, hdr2))55break;5657if ((hdr1 & 0x1f) == 0xf) {58/* 2-byte header format */59blk_idx = get_efuse_blk_idx_2_byte(hdr1, hdr2);60word_en = hdr2 & 0xf;61phy_idx += 2;62} else {63/* 1-byte header format */64blk_idx = get_efuse_blk_idx_1_byte(hdr1);65word_en = hdr1 & 0xf;66phy_idx += 1;67}6869for (i = 0; i < 4; i++) {70if (invalid_efuse_content(word_en, i))71continue;7273log_idx = block_idx_to_logical_idx(blk_idx, i);74if (phy_idx + 1 > physical_size - protect_size ||75log_idx + 1 > logical_size)76return -EINVAL;7778log_map[log_idx] = phy_map[phy_idx];79log_map[log_idx + 1] = phy_map[phy_idx + 1];80phy_idx += 2;81}82}83return 0;84}8586static int rtw_dump_physical_efuse_map(struct rtw_dev *rtwdev, u8 *map)87{88const struct rtw_chip_info *chip = rtwdev->chip;89u32 size = rtwdev->efuse.physical_size;90u32 efuse_ctl;91u32 addr;92u32 cnt;9394rtw_chip_efuse_grant_on(rtwdev);9596switch_efuse_bank(rtwdev);9798/* disable 2.5V LDO */99chip->ops->cfg_ldo25(rtwdev, false);100101efuse_ctl = rtw_read32(rtwdev, REG_EFUSE_CTRL);102103for (addr = 0; addr < size; addr++) {104efuse_ctl &= ~(BIT_MASK_EF_DATA | BITS_EF_ADDR);105efuse_ctl |= (addr & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR;106rtw_write32(rtwdev, REG_EFUSE_CTRL, efuse_ctl & (~BIT_EF_FLAG));107108cnt = 1000000;109do {110udelay(1);111efuse_ctl = rtw_read32(rtwdev, REG_EFUSE_CTRL);112if (--cnt == 0)113return -EBUSY;114} while (!(efuse_ctl & BIT_EF_FLAG));115116*(map + addr) = (u8)(efuse_ctl & BIT_MASK_EF_DATA);117}118119rtw_chip_efuse_grant_off(rtwdev);120121return 0;122}123124int rtw_read8_physical_efuse(struct rtw_dev *rtwdev, u16 addr, u8 *data)125{126u32 efuse_ctl;127int ret;128129rtw_write32_mask(rtwdev, REG_EFUSE_CTRL, 0x3ff00, addr);130rtw_write32_clr(rtwdev, REG_EFUSE_CTRL, BIT_EF_FLAG);131132ret = read_poll_timeout(rtw_read32, efuse_ctl, efuse_ctl & BIT_EF_FLAG,1331000, 100000, false, rtwdev, REG_EFUSE_CTRL);134if (ret) {135*data = EFUSE_READ_FAIL;136return ret;137}138139*data = rtw_read8(rtwdev, REG_EFUSE_CTRL);140141return 0;142}143EXPORT_SYMBOL(rtw_read8_physical_efuse);144145int rtw_parse_efuse_map(struct rtw_dev *rtwdev)146{147const struct rtw_chip_info *chip = rtwdev->chip;148struct rtw_efuse *efuse = &rtwdev->efuse;149u32 phy_size = efuse->physical_size;150u32 log_size = efuse->logical_size;151u8 *phy_map = NULL;152u8 *log_map = NULL;153int ret = 0;154155phy_map = kmalloc(phy_size, GFP_KERNEL);156log_map = kmalloc(log_size, GFP_KERNEL);157if (!phy_map || !log_map) {158ret = -ENOMEM;159goto out_free;160}161162ret = rtw_dump_physical_efuse_map(rtwdev, phy_map);163if (ret) {164rtw_err(rtwdev, "failed to dump efuse physical map\n");165goto out_free;166}167168memset(log_map, 0xff, log_size);169ret = rtw_dump_logical_efuse_map(rtwdev, phy_map, log_map);170if (ret) {171rtw_err(rtwdev, "failed to dump efuse logical map\n");172goto out_free;173}174175ret = chip->ops->read_efuse(rtwdev, log_map);176if (ret) {177rtw_err(rtwdev, "failed to read efuse map\n");178goto out_free;179}180181out_free:182kfree(log_map);183kfree(phy_map);184185return ret;186}187188189