Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  eeprom.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
 * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
 */


#include <linux/of.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/etherdevice.h>
#include <linux/unaligned.h>
#include "mt7601u.h"
#include "eeprom.h"
#include "mac.h"

static bool
field_valid(u8 val)
{
 return val != 0xff;
}

static s8
field_validate(u8 val)
{
 if (!field_valid(val))
  return 0;

 return val;
}

static int
mt7601u_efuse_read(struct mt7601u_dev *dev, u16 addr, u8 *data,
     enum mt7601u_eeprom_access_modes mode)
{
 u32 val;
 int i;

 val = mt76_rr(dev, MT_EFUSE_CTRL);
 val &= ~(MT_EFUSE_CTRL_AIN |
   MT_EFUSE_CTRL_MODE);
 val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf) |
        FIELD_PREP(MT_EFUSE_CTRL_MODE, mode) |
        MT_EFUSE_CTRL_KICK;
 mt76_wr(dev, MT_EFUSE_CTRL, val);

 if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
  return -ETIMEDOUT;

 val = mt76_rr(dev, MT_EFUSE_CTRL);
 if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) {
  /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0)
 * will not return valid data but it's ok.
 */

  memset(data, 0xff, 16);
  return 0;
 }

 for (i = 0; i < 4; i++) {
  val = mt76_rr(dev, MT_EFUSE_DATA(i));
  put_unaligned_le32(val, data + 4 * i);
 }

 return 0;
}

static int
mt7601u_efuse_physical_size_check(struct mt7601u_dev *dev)
{
 const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16);
 u8 data[round_up(MT_EFUSE_USAGE_MAP_SIZE, 16)];
 int ret, i;
 u32 start = 0, end = 0, cnt_free;

 for (i = 0; i < map_reads; i++) {
  ret = mt7601u_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16,
      data + i * 16, MT_EE_PHYSICAL_READ);
  if (ret)
   return ret;
 }

 for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++)
  if (!data[i]) {
   if (!start)
    start = MT_EE_USAGE_MAP_START + i;
   end = MT_EE_USAGE_MAP_START + i;
  }
 cnt_free = end - start + 1;

 if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) {
  dev_err(dev->dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n");
  return -EINVAL;
 }

 return 0;
}

static bool
mt7601u_has_tssi(struct mt7601u_dev *dev, u8 *eeprom)
{
 u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);

 return (u16)~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN);
}

static void
mt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom)
{
 u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0);
 u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1);

 if (!field_valid(nic_conf1 & 0xff))
  nic_conf1 &= 0xff00;

 dev->ee->tssi_enabled = mt7601u_has_tssi(dev, eeprom) &&
    !(nic_conf1 & MT_EE_NIC_CONF_1_TEMP_TX_ALC);

 if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL)
  dev_err(dev->dev,
   "Error: this driver does not support HW RF ctrl\n");

 if (!field_valid(nic_conf0 >> 8))
  return;

 if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 ||
     FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1)
  dev_err(dev->dev,
   "Error: device has more than 1 RX/TX stream!\n");
}

static void mt7601u_set_channel_target_power(struct mt7601u_dev *dev,
          u8 *eeprom, u8 max_pwr)
{
 u8 trgt_pwr = eeprom[MT_EE_TX_TSSI_TARGET_POWER];

 if (trgt_pwr > max_pwr || !trgt_pwr) {
  dev_warn(dev->dev, "Error: EEPROM trgt power invalid %hhx!\n",
    trgt_pwr);
  trgt_pwr = 0x20;
 }

 memset(dev->ee->chan_pwr, trgt_pwr, sizeof(dev->ee->chan_pwr));
}

static void
mt7601u_set_channel_power(struct mt7601u_dev *dev, u8 *eeprom)
{
 u32 i, val;
 u8 max_pwr;

 val = mt7601u_rr(dev, MT_TX_ALC_CFG_0);
 max_pwr = FIELD_GET(MT_TX_ALC_CFG_0_LIMIT_0, val);

 if (mt7601u_has_tssi(dev, eeprom)) {
  mt7601u_set_channel_target_power(dev, eeprom, max_pwr);
  return;
 }

 for (i = 0; i < 14; i++) {
  s8 power = field_validate(eeprom[MT_EE_TX_POWER_OFFSET + i]);

  if (power > max_pwr || power < 0)
   power = MT7601U_DEFAULT_TX_POWER;

  dev->ee->chan_pwr[i] = power;
 }
}

static void
mt7601u_set_country_reg(struct mt7601u_dev *dev, u8 *eeprom)
{
 /* Note: - region 31 is not valid for mt7601u (see rtmp_init.c)
 *  - comments in rtmp_def.h are incorrect (see rt_channel.c)
 */

 static const struct reg_channel_bounds chan_bounds[] = {
  /* EEPROM country regions 0 - 7 */
  {  1, 11 }, {  1, 13 }, { 10,  2 }, { 10,  4 },
  { 14,  1 }, {  1, 14 }, {  3,  7 }, {  5,  9 },
  /* EEPROM country regions 32 - 33 */
  {  1, 11 }, {  1, 14 }
 };
 u8 val = eeprom[MT_EE_COUNTRY_REGION];
 int idx = -1;

 if (val < 8)
  idx = val;
 if (val > 31 && val < 33)
  idx = val - 32 + 8;

 if (idx != -1)
  dev_info(dev->dev,
    "EEPROM country region %02x (channels %d-%d)\n",
    val, chan_bounds[idx].start,
    chan_bounds[idx].start + chan_bounds[idx].num - 1);
 else
  idx = 5; /* channels 1 - 14 */

 dev->ee->reg = chan_bounds[idx];

 /* TODO: country region 33 is special - phy should be set to B-mode
 *  before entering channel 14 (see sta/connect.c)
 */

}

static void
mt7601u_set_rf_freq_off(struct mt7601u_dev *dev, u8 *eeprom)
{
 u8 comp;

 dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]);
 comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]);

 if (comp & BIT(7))
  dev->ee->rf_freq_off -= comp & 0x7f;
 else
  dev->ee->rf_freq_off += comp;
}

static void
mt7601u_set_rssi_offset(struct mt7601u_dev *dev, u8 *eeprom)
{
 int i;
 s8 *rssi_offset = dev->ee->rssi_offset;

 for (i = 0; i < 2; i++) {
  rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i];

  if (rssi_offset[i] < -10 || rssi_offset[i] > 10) {
   dev_warn(dev->dev,
     "Warning: EEPROM RSSI is invalid %02hhx\n",
     rssi_offset[i]);
   rssi_offset[i] = 0;
  }
 }
}

static void
mt7601u_extra_power_over_mac(struct mt7601u_dev *dev)
{
 u32 val;

 val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_1) & 0x0000ff00) >> 8);
 val |= ((mt7601u_rr(dev, MT_TX_PWR_CFG_2) & 0x0000ff00) << 8);
 mt7601u_wr(dev, MT_TX_PWR_CFG_7, val);

 val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8);
 mt7601u_wr(dev, MT_TX_PWR_CFG_9, val);
}

static void
mt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value)
{
 /* Invalid? Note: vendor driver does not handle this */
 if (value == 0xff)
  return;

 rate->raw = s6_validate(value);
 rate->bw20 = s6_to_int(value);
 /* Note: vendor driver does cap the value to s6 right away */
 rate->bw40 = rate->bw20 + delta;
}

static void
mt7601u_save_power_rate(struct mt7601u_dev *dev, s8 delta, u32 val, int i)
{
 struct mt7601u_rate_power *t = &dev->ee->power_rate_table;

 switch (i) {
 case 0:
  mt7601u_set_power_rate(&t->cck[0], delta, (val >> 0) & 0xff);
  mt7601u_set_power_rate(&t->cck[1], delta, (val >> 8) & 0xff);
  /* Save cck bw20 for fixups of channel 14 */
  dev->ee->real_cck_bw20[0] = t->cck[0].bw20;
  dev->ee->real_cck_bw20[1] = t->cck[1].bw20;

  mt7601u_set_power_rate(&t->ofdm[0], delta, (val >> 16) & 0xff);
  mt7601u_set_power_rate(&t->ofdm[1], delta, (val >> 24) & 0xff);
  break;
 case 1:
  mt7601u_set_power_rate(&t->ofdm[2], delta, (val >> 0) & 0xff);
  mt7601u_set_power_rate(&t->ofdm[3], delta, (val >> 8) & 0xff);
  mt7601u_set_power_rate(&t->ht[0], delta, (val >> 16) & 0xff);
  mt7601u_set_power_rate(&t->ht[1], delta, (val >> 24) & 0xff);
  break;
 case 2:
  mt7601u_set_power_rate(&t->ht[2], delta, (val >> 0) & 0xff);
  mt7601u_set_power_rate(&t->ht[3], delta, (val >> 8) & 0xff);
  break;
 }
}

static s8
get_delta(u8 val)
{
 s8 ret;

 if (!field_valid(val) || !(val & BIT(7)))
  return 0;

 ret = val & 0x1f;
 if (ret > 8)
  ret = 8;
 if (val & BIT(6))
  ret = -ret;

 return ret;
}

static void
mt7601u_config_tx_power_per_rate(struct mt7601u_dev *dev, u8 *eeprom)
{
 u32 val;
 s8 bw40_delta;
 int i;

 bw40_delta = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]);

 for (i = 0; i < 5; i++) {
  val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i));

  mt7601u_save_power_rate(dev, bw40_delta, val, i);

  if (~val)
   mt7601u_wr(dev, MT_TX_PWR_CFG_0 + i * 4, val);
 }

 mt7601u_extra_power_over_mac(dev);
}

static void
mt7601u_init_tssi_params(struct mt7601u_dev *dev, u8 *eeprom)
{
 struct tssi_data *d = &dev->ee->tssi_data;

 if (!dev->ee->tssi_enabled)
  return;

 d->slope = eeprom[MT_EE_TX_TSSI_SLOPE];
 d->tx0_delta_offset = eeprom[MT_EE_TX_TSSI_OFFSET] * 1024;
 d->offset[0] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP];
 d->offset[1] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 1];
 d->offset[2] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 2];
}

int
mt7601u_eeprom_init(struct mt7601u_dev *dev)
{
 u8 *eeprom;
 int i, ret;

 ret = mt7601u_efuse_physical_size_check(dev);
 if (ret)
  return ret;

 dev->ee = devm_kzalloc(dev->dev, sizeof(*dev->ee), GFP_KERNEL);
 if (!dev->ee)
  return -ENOMEM;

 eeprom = kmalloc(MT7601U_EEPROM_SIZE, GFP_KERNEL);
 if (!eeprom)
  return -ENOMEM;

 for (i = 0; i + 16 <= MT7601U_EEPROM_SIZE; i += 16) {
  ret = mt7601u_efuse_read(dev, i, eeprom + i, MT_EE_READ);
  if (ret)
   goto out;
 }

 if (eeprom[MT_EE_VERSION_EE] > MT7601U_EE_MAX_VER)
  dev_warn(dev->dev,
    "Warning: unsupported EEPROM version %02hhx\n",
    eeprom[MT_EE_VERSION_EE]);
 dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n",
   eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]);

 mt7601u_set_macaddr(dev, eeprom + MT_EE_MAC_ADDR);
 mt7601u_set_chip_cap(dev, eeprom);
 mt7601u_set_channel_power(dev, eeprom);
 mt7601u_set_country_reg(dev, eeprom);
 mt7601u_set_rf_freq_off(dev, eeprom);
 mt7601u_set_rssi_offset(dev, eeprom);
 dev->ee->ref_temp = eeprom[MT_EE_REF_TEMP];
 dev->ee->lna_gain = eeprom[MT_EE_LNA_GAIN];

 mt7601u_config_tx_power_per_rate(dev, eeprom);

 mt7601u_init_tssi_params(dev, eeprom);
out:
 kfree(eeprom);
 return ret;
}

Messung V0.5
C=96 H=94 G=94

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge