Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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}