linux/drivers/net/wireless/realtek/rtw88/efuse.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/* Copyright(c) 2018-2019  Realtek Corporation
   3 */
   4
   5#include "main.h"
   6#include "efuse.h"
   7#include "reg.h"
   8#include "debug.h"
   9
  10#define RTW_EFUSE_BANK_WIFI             0x0
  11
  12static void switch_efuse_bank(struct rtw_dev *rtwdev)
  13{
  14        rtw_write32_mask(rtwdev, REG_LDO_EFUSE_CTRL, BIT_MASK_EFUSE_BANK_SEL,
  15                         RTW_EFUSE_BANK_WIFI);
  16}
  17
  18#define invalid_efuse_header(hdr1, hdr2) \
  19        ((hdr1) == 0xff || (((hdr1) & 0x1f) == 0xf && (hdr2) == 0xff))
  20#define invalid_efuse_content(word_en, i) \
  21        (((word_en) & BIT(i)) != 0x0)
  22#define get_efuse_blk_idx_2_byte(hdr1, hdr2) \
  23        ((((hdr2) & 0xf0) >> 1) | (((hdr1) >> 5) & 0x07))
  24#define get_efuse_blk_idx_1_byte(hdr1) \
  25        (((hdr1) & 0xf0) >> 4)
  26#define block_idx_to_logical_idx(blk_idx, i) \
  27        (((blk_idx) << 3) + ((i) << 1))
  28
  29/* efuse header format
  30 *
  31 * | 7        5   4    0 | 7        4   3          0 | 15  8  7   0 |
  32 *   block[2:0]   0 1111   block[6:3]   word_en[3:0]   byte0  byte1
  33 * | header 1 (optional) |          header 2         |    word N    |
  34 *
  35 * word_en: 4 bits each word. 0 -> write; 1 -> not write
  36 * N: 1~4, depends on word_en
  37 */
  38static int rtw_dump_logical_efuse_map(struct rtw_dev *rtwdev, u8 *phy_map,
  39                                      u8 *log_map)
  40{
  41        u32 physical_size = rtwdev->efuse.physical_size;
  42        u32 protect_size = rtwdev->efuse.protect_size;
  43        u32 logical_size = rtwdev->efuse.logical_size;
  44        u32 phy_idx, log_idx;
  45        u8 hdr1, hdr2;
  46        u8 blk_idx;
  47        u8 word_en;
  48        int i;
  49
  50        for (phy_idx = 0; phy_idx < physical_size - protect_size;) {
  51                hdr1 = phy_map[phy_idx];
  52                hdr2 = phy_map[phy_idx + 1];
  53                if (invalid_efuse_header(hdr1, hdr2))
  54                        break;
  55
  56                if ((hdr1 & 0x1f) == 0xf) {
  57                        /* 2-byte header format */
  58                        blk_idx = get_efuse_blk_idx_2_byte(hdr1, hdr2);
  59                        word_en = hdr2 & 0xf;
  60                        phy_idx += 2;
  61                } else {
  62                        /* 1-byte header format */
  63                        blk_idx = get_efuse_blk_idx_1_byte(hdr1);
  64                        word_en = hdr1 & 0xf;
  65                        phy_idx += 1;
  66                }
  67
  68                for (i = 0; i < 4; i++) {
  69                        if (invalid_efuse_content(word_en, i))
  70                                continue;
  71
  72                        log_idx = block_idx_to_logical_idx(blk_idx, i);
  73                        if (phy_idx + 1 > physical_size - protect_size ||
  74                            log_idx + 1 > logical_size)
  75                                return -EINVAL;
  76
  77                        log_map[log_idx] = phy_map[phy_idx];
  78                        log_map[log_idx + 1] = phy_map[phy_idx + 1];
  79                        phy_idx += 2;
  80                }
  81        }
  82        return 0;
  83}
  84
  85static int rtw_dump_physical_efuse_map(struct rtw_dev *rtwdev, u8 *map)
  86{
  87        struct rtw_chip_info *chip = rtwdev->chip;
  88        u32 size = rtwdev->efuse.physical_size;
  89        u32 efuse_ctl;
  90        u32 addr;
  91        u32 cnt;
  92
  93        switch_efuse_bank(rtwdev);
  94
  95        /* disable 2.5V LDO */
  96        chip->ops->cfg_ldo25(rtwdev, false);
  97
  98        efuse_ctl = rtw_read32(rtwdev, REG_EFUSE_CTRL);
  99
 100        for (addr = 0; addr < size; addr++) {
 101                efuse_ctl &= ~(BIT_MASK_EF_DATA | BITS_EF_ADDR);
 102                efuse_ctl |= (addr & BIT_MASK_EF_ADDR) << BIT_SHIFT_EF_ADDR;
 103                rtw_write32(rtwdev, REG_EFUSE_CTRL, efuse_ctl & (~BIT_EF_FLAG));
 104
 105                cnt = 1000000;
 106                do {
 107                        udelay(1);
 108                        efuse_ctl = rtw_read32(rtwdev, REG_EFUSE_CTRL);
 109                        if (--cnt == 0)
 110                                return -EBUSY;
 111                } while (!(efuse_ctl & BIT_EF_FLAG));
 112
 113                *(map + addr) = (u8)(efuse_ctl & BIT_MASK_EF_DATA);
 114        }
 115
 116        return 0;
 117}
 118
 119int rtw_parse_efuse_map(struct rtw_dev *rtwdev)
 120{
 121        struct rtw_chip_info *chip = rtwdev->chip;
 122        struct rtw_efuse *efuse = &rtwdev->efuse;
 123        u32 phy_size = efuse->physical_size;
 124        u32 log_size = efuse->logical_size;
 125        u8 *phy_map = NULL;
 126        u8 *log_map = NULL;
 127        int ret = 0;
 128
 129        phy_map = kmalloc(phy_size, GFP_KERNEL);
 130        log_map = kmalloc(log_size, GFP_KERNEL);
 131        if (!phy_map || !log_map) {
 132                ret = -ENOMEM;
 133                goto out_free;
 134        }
 135
 136        ret = rtw_dump_physical_efuse_map(rtwdev, phy_map);
 137        if (ret) {
 138                rtw_err(rtwdev, "failed to dump efuse physical map\n");
 139                goto out_free;
 140        }
 141
 142        memset(log_map, 0xff, log_size);
 143        ret = rtw_dump_logical_efuse_map(rtwdev, phy_map, log_map);
 144        if (ret) {
 145                rtw_err(rtwdev, "failed to dump efuse logical map\n");
 146                goto out_free;
 147        }
 148
 149        ret = chip->ops->read_efuse(rtwdev, log_map);
 150        if (ret) {
 151                rtw_err(rtwdev, "failed to read efuse map\n");
 152                goto out_free;
 153        }
 154
 155out_free:
 156        kfree(log_map);
 157        kfree(phy_map);
 158
 159        return ret;
 160}
 161