root/drivers/net/wireless/realtek/rtw88/efuse.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. switch_efuse_bank
  2. rtw_dump_logical_efuse_map
  3. rtw_dump_physical_efuse_map
  4. rtw_parse_efuse_map

   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 
  12 static 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  */
  38 static 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 
  85 static 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 
 119 int 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 
 155 out_free:
 156         kfree(log_map);
 157         kfree(phy_map);
 158 
 159         return ret;
 160 }

/* [<][>][^][v][top][bottom][index][help] */