diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c
index 39c2c846f808..46327cc90797 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/debugfs.c
@@ -118,19 +118,6 @@ mt76x0_eeprom_param_read(struct seq_file *file, void *data)
 	for (i = 0; i < 58; i++)
 		seq_printf(file, "\t%d chan:%d pwr:%d\n", i, i,
 			   dev->ee->tx_pwr_per_chan[i]);
-
-	seq_puts(file, "Per rate power 2GHz:\n");
-	for (i = 0; i < 5; i++)
-		seq_printf(file, "\t %d bw20:%d bw40:%d\n",
-			   i, dev->ee->tx_pwr_cfg_2g[i][0],
-			      dev->ee->tx_pwr_cfg_5g[i][1]);
-
-	seq_puts(file, "Per rate power 5GHz:\n");
-	for (i = 0; i < 5; i++)
-		seq_printf(file, "\t %d bw20:%d bw40:%d\n",
-			   i, dev->ee->tx_pwr_cfg_5g[i][0],
-			      dev->ee->tx_pwr_cfg_5g[i][1]);
-
 	return 0;
 }
 
@@ -147,6 +134,23 @@ static const struct file_operations fops_eeprom_param = {
 	.release = single_release,
 };
 
+static int mt76x0_read_txpower(struct seq_file *file, void *data)
+{
+	struct mt76x0_dev *dev = dev_get_drvdata(file->private);
+
+	mt76_seq_puts_array(file, "CCK", dev->caldata.rate_power.cck,
+			    ARRAY_SIZE(dev->caldata.rate_power.cck));
+	mt76_seq_puts_array(file, "OFDM", dev->caldata.rate_power.ofdm,
+			    ARRAY_SIZE(dev->caldata.rate_power.ofdm));
+	mt76_seq_puts_array(file, "STBC", dev->caldata.rate_power.stbc,
+			    ARRAY_SIZE(dev->caldata.rate_power.stbc));
+	mt76_seq_puts_array(file, "HT", dev->caldata.rate_power.ht,
+			    ARRAY_SIZE(dev->caldata.rate_power.ht));
+	mt76_seq_puts_array(file, "VHT", dev->caldata.rate_power.vht,
+			    ARRAY_SIZE(dev->caldata.rate_power.vht));
+	return 0;
+}
+
 void mt76x0_init_debugfs(struct mt76x0_dev *dev)
 {
 	struct dentry *dir;
@@ -161,4 +165,6 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev)
 	debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat);
 	debugfs_create_file("eeprom_param", S_IRUSR, dir, dev,
 			    &fops_eeprom_param);
+	debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir,
+				    mt76x0_read_txpower);
 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
index f9d917a7f3f5..1406e88141de 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
@@ -125,82 +125,103 @@ void mt76x0_read_rx_gain(struct mt76x0_dev *dev)
 	}
 }
 
-static u32
-calc_bw40_power_rate(u32 value, int delta)
+static s8 mt76x0_get_power_rate(u8 val, s8 delta)
 {
-	u32 ret = 0;
-	int i, tmp;
-
-	for (i = 0; i < 4; i++) {
-		tmp = s6_to_int((value >> i*8) & 0xff) + delta;
-		ret |= (u32)(int_to_s6(tmp)) << i*8;
-	}
-
-	return ret;
+	return s6_to_s8(val) + delta;
 }
 
-static s8
-get_delta(u8 val)
+static s8 mt76x0_get_delta(struct mt76_dev *dev,
+			   struct cfg80211_chan_def *chandef)
 {
+	u8 val;
 	s8 ret;
 
+	if (mt76x02_tssi_enabled(dev))
+		return 0;
+
+	if (chandef->width == NL80211_CHAN_WIDTH_80) {
+		val = mt76x02_eeprom_get(dev, MT_EE_5G_TARGET_POWER) >> 8;
+	} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
+		u16 data;
+
+		data = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40);
+		if (chandef->chan->band == NL80211_BAND_5GHZ)
+			val = data >> 8;
+		else
+			val = data;
+	} else {
+		return 0;
+	}
+
 	if (!mt76x02_field_valid(val) || !(val & BIT(7)))
 		return 0;
 
 	ret = val & 0x1f;
 	if (ret > 8)
-		ret = 8;
-	if (val & BIT(6))
-		ret = -ret;
+		return 8;
 
-	return ret;
+	return (val & BIT(6)) ? -ret : ret;
 }
 
-static void
-mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev, u8 *eeprom)
+void mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev,
+				  struct cfg80211_chan_def *chandef)
 {
-	s8 bw40_delta_2g, bw40_delta_5g;
-	u32 val;
-	int i;
-
-	bw40_delta_2g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]);
-	bw40_delta_5g = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40 + 1]);
-
-	for (i = 0; i < 5; i++) {
-		val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i));
-
-		/* Skip last 16 bits. */
-		if (i == 4)
-			val &= 0x0000ffff;
-
-		dev->ee->tx_pwr_cfg_2g[i][0] = val;
-		dev->ee->tx_pwr_cfg_2g[i][1] = calc_bw40_power_rate(val, bw40_delta_2g);
-	}
-
-	/* Reading per rate tx power for 5 GHz band is a bit more complex. Note
-	 * we mix 16 bit and 32 bit reads and sometimes do shifts.
-	 */
-	val = get_unaligned_le16(eeprom + 0x120);
-	val <<= 16;
-	dev->ee->tx_pwr_cfg_5g[0][0] = val;
-	dev->ee->tx_pwr_cfg_5g[0][1] = calc_bw40_power_rate(val, bw40_delta_5g);
-
-	val = get_unaligned_le32(eeprom + 0x122);
-	dev->ee->tx_pwr_cfg_5g[1][0] = val;
-	dev->ee->tx_pwr_cfg_5g[1][1] = calc_bw40_power_rate(val, bw40_delta_5g);
-
-	val = get_unaligned_le16(eeprom + 0x126);
-	dev->ee->tx_pwr_cfg_5g[2][0] = val;
-	dev->ee->tx_pwr_cfg_5g[2][1] = calc_bw40_power_rate(val, bw40_delta_5g);
-
-	val = get_unaligned_le16(eeprom + 0xec);
-	val <<= 16;
-	dev->ee->tx_pwr_cfg_5g[3][0] = val;
-	dev->ee->tx_pwr_cfg_5g[3][1] = calc_bw40_power_rate(val, bw40_delta_5g);
-
-	val = get_unaligned_le16(eeprom + 0xee);
-	dev->ee->tx_pwr_cfg_5g[4][0] = val;
-	dev->ee->tx_pwr_cfg_5g[4][1] = calc_bw40_power_rate(val, bw40_delta_5g);
+	bool is_2ghz = chandef->chan->band == NL80211_BAND_2GHZ;
+	s8 data, delta = mt76x0_get_delta(&dev->mt76, chandef);
+	struct mt76_rate_power *t = &dev->caldata.rate_power;
+	struct mt76_dev *mdev = &dev->mt76;
+	u16 val, addr;
+
+	memset(t, 0, sizeof(*t));
+
+	/* cck 1M, 2M, 5.5M, 11M */
+	val = mt76x02_eeprom_get(mdev, MT_EE_TX_POWER_BYRATE_BASE);
+	t->cck[0] = t->cck[1] = mt76x0_get_power_rate(val, delta);
+	t->cck[2] = t->cck[3] = mt76x0_get_power_rate(val >> 8, delta);
+
+	/* ofdm 6M, 9M, 12M, 18M */
+	addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 2 : 0x120;
+	val = mt76x02_eeprom_get(mdev, addr);
+	t->ofdm[0] = t->ofdm[1] = mt76x0_get_power_rate(val, delta);
+	t->ofdm[2] = t->ofdm[3] = mt76x0_get_power_rate(val >> 8, delta);
+
+	/* ofdm 24M, 36M, 48M, 54M */
+	addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 4 : 0x122;
+	val = mt76x02_eeprom_get(mdev, addr);
+	t->ofdm[4] = t->ofdm[5] = mt76x0_get_power_rate(val, delta);
+	t->ofdm[6] = t->ofdm[7] = mt76x0_get_power_rate(val >> 8, delta);
+
+	/* ht-vht mcs 1ss 0, 1, 2, 3 */
+	addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 6 : 0x124;
+	val = mt76x02_eeprom_get(mdev, addr);
+	data = mt76x0_get_power_rate(val, delta);
+	t->ht[0] = t->ht[1] = t->vht[0] = t->vht[1] = data;
+	data = mt76x0_get_power_rate(val >> 8, delta);
+	t->ht[2] = t->ht[3] = t->vht[2] = t->vht[3] = data;
+
+	/* ht-vht mcs 1ss 4, 5, 6 */
+	addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 8 : 0x126;
+	val = mt76x02_eeprom_get(mdev, addr);
+	data = mt76x0_get_power_rate(val, delta);
+	t->ht[4] = t->ht[5] = t->vht[4] = t->vht[5] = data;
+	t->ht[6] = t->vht[6] = mt76x0_get_power_rate(val >> 8, delta);
+
+	/* ht-vht mcs 1ss 0, 1, 2, 3 stbc */
+	addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 14 : 0xec;
+	val = mt76x02_eeprom_get(mdev, addr);
+	t->stbc[0] = t->stbc[1] = mt76x0_get_power_rate(val, delta);
+	t->stbc[2] = t->stbc[3] = mt76x0_get_power_rate(val >> 8, delta);
+
+	/* ht-vht mcs 1ss 4, 5, 6 stbc */
+	addr = is_2ghz ? MT_EE_TX_POWER_BYRATE_BASE + 16 : 0xee;
+	val = mt76x02_eeprom_get(mdev, addr);
+	t->stbc[4] = t->stbc[5] = mt76x0_get_power_rate(val, delta);
+	t->stbc[6] = t->stbc[7] = mt76x0_get_power_rate(val >> 8, delta);
+
+	/* vht mcs 8, 9 5GHz */
+	val = mt76x02_eeprom_get(mdev, 0x132);
+	t->vht[7] = mt76x0_get_power_rate(val, delta);
+	t->vht[8] = mt76x0_get_power_rate(val >> 8, delta);
 }
 
 static void
@@ -271,7 +292,6 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev)
 	mt76x0_set_temp_offset(dev);
 	dev->chainmask = 0x0101;
 
-	mt76x0_set_tx_power_per_rate(dev, eeprom);
 	mt76x0_set_tx_power_per_chan(dev, eeprom);
 
 out:
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h
index 8006d08cba45..88e31186c317 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.h
@@ -34,34 +34,27 @@ struct mt76x0_caldata {
 
 	s16 temp_offset;
 	u8 freq_offset;
+
+	struct mt76_rate_power rate_power;
 };
 
 struct mt76x0_eeprom_params {
-	/* TX_PWR_CFG_* values from EEPROM for 20 and 40 Mhz bandwidths. */
-	u32 tx_pwr_cfg_2g[5][2];
-	u32 tx_pwr_cfg_5g[5][2];
 
 	u8 tx_pwr_per_chan[58];
 };
 
 int mt76x0_eeprom_init(struct mt76x0_dev *dev);
 void mt76x0_read_rx_gain(struct mt76x0_dev *dev);
+void mt76x0_set_tx_power_per_rate(struct mt76x0_dev *dev,
+				  struct cfg80211_chan_def *chandef);
 
-static inline u32 s6_validate(u32 reg)
+static inline s8 s6_to_s8(u32 val)
 {
-	WARN_ON(reg & ~GENMASK(5, 0));
-	return reg & GENMASK(5, 0);
-}
-
-static inline int s6_to_int(u32 reg)
-{
-	int s6;
-
-	s6 = s6_validate(reg);
-	if (s6 & BIT(5))
-		s6 -= BIT(6);
+	s8 ret = val & GENMASK(5, 0);
 
-	return s6;
+	if (ret & BIT(5))
+		ret -= BIT(6);
+	return ret;
 }
 
 static inline u32 int_to_s6(int val)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index c3db4c1cd4fe..52cd39fbfd49 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -566,21 +566,16 @@ mt76x0_extra_power_over_mac(struct mt76x0_dev *dev)
 }
 
 static void
-mt76x0_phy_set_tx_power(struct mt76x0_dev *dev, u8 channel, u8 rf_bw_band)
+mt76x0_phy_set_tx_power(struct mt76x0_dev *dev, u8 rf_bw_band)
 {
+	struct mt76x0_caldata *caldata = &dev->caldata;
+	int i, bw = (rf_bw_band & RF_BW_20) ? 0 : 1;
 	u32 val;
-	int i;
-	int bw = (rf_bw_band & RF_BW_20) ? 0 : 1;
 
 	for (i = 0; i < 4; i++) {
-		if (channel <= 14)
-			val = dev->ee->tx_pwr_cfg_2g[i][bw];
-		else
-			val = dev->ee->tx_pwr_cfg_5g[i][bw];
-
-		mt76_wr(dev, MT_TX_PWR_CFG_0 + 4*i, val);
+		val = caldata->tx_pwr_cfg[i][bw];
+		mt76_wr(dev, MT_TX_PWR_CFG_0 + 4 * i, val);
 	}
-
 	mt76x0_extra_power_over_mac(dev);
 }
 #endif
@@ -716,6 +711,7 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
 
 	mt76x0_phy_set_band(dev, chandef->chan->band);
 	mt76x0_phy_set_chan_rf_params(dev, channel, rf_bw_band);
+	mt76x0_set_tx_power_per_rate(dev, chandef);
 	mt76x0_read_rx_gain(dev);
 
 	/* set Japan Tx filter at channel 14 */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h
index 9339514fb073..ca9554ac8f26 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h
@@ -74,6 +74,7 @@ enum mt76x02_eeprom_field {
 
 	MT_EE_2G_TARGET_POWER =			0x0d0,
 	MT_EE_TEMP_OFFSET =			0x0d1,
+	MT_EE_5G_TARGET_POWER =			0x0d2,
 	MT_EE_TSSI_BOUND1 =			0x0d4,
 	MT_EE_TSSI_BOUND2 =			0x0d6,
 	MT_EE_TSSI_BOUND3 =			0x0d8,
@@ -121,9 +122,6 @@ enum mt76x02_eeprom_field {
 #define MT_EE_NIC_CONF_2_TEMP_DISABLE		BIT(11)
 #define MT_EE_NIC_CONF_2_COEX_METHOD		GENMASK(15, 13)
 
-#define MT_EE_TX_POWER_BYRATE(x)		(MT_EE_TX_POWER_BYRATE_BASE + \
-						 (x) * 4)
-
 #define MT_EFUSE_USAGE_MAP_SIZE			(MT_EE_USAGE_MAP_END - \
 						 MT_EE_USAGE_MAP_START + 1)
 
