Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003 
0004   Broadcom B43 wireless driver
0005   Common PHY routines
0006 
0007   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
0008   Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
0009   Copyright (c) 2005-2008 Michael Buesch <m@bues.ch>
0010   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
0011   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
0012 
0013 
0014 */
0015 
0016 #include "phy_common.h"
0017 #include "phy_g.h"
0018 #include "phy_a.h"
0019 #include "phy_n.h"
0020 #include "phy_lp.h"
0021 #include "phy_ht.h"
0022 #include "phy_lcn.h"
0023 #include "phy_ac.h"
0024 #include "b43.h"
0025 #include "main.h"
0026 
0027 
0028 int b43_phy_allocate(struct b43_wldev *dev)
0029 {
0030     struct b43_phy *phy = &(dev->phy);
0031     int err;
0032 
0033     phy->ops = NULL;
0034 
0035     switch (phy->type) {
0036     case B43_PHYTYPE_G:
0037 #ifdef CONFIG_B43_PHY_G
0038         phy->ops = &b43_phyops_g;
0039 #endif
0040         break;
0041     case B43_PHYTYPE_N:
0042 #ifdef CONFIG_B43_PHY_N
0043         phy->ops = &b43_phyops_n;
0044 #endif
0045         break;
0046     case B43_PHYTYPE_LP:
0047 #ifdef CONFIG_B43_PHY_LP
0048         phy->ops = &b43_phyops_lp;
0049 #endif
0050         break;
0051     case B43_PHYTYPE_HT:
0052 #ifdef CONFIG_B43_PHY_HT
0053         phy->ops = &b43_phyops_ht;
0054 #endif
0055         break;
0056     case B43_PHYTYPE_LCN:
0057 #ifdef CONFIG_B43_PHY_LCN
0058         phy->ops = &b43_phyops_lcn;
0059 #endif
0060         break;
0061     case B43_PHYTYPE_AC:
0062 #ifdef CONFIG_B43_PHY_AC
0063         phy->ops = &b43_phyops_ac;
0064 #endif
0065         break;
0066     }
0067     if (B43_WARN_ON(!phy->ops))
0068         return -ENODEV;
0069 
0070     err = phy->ops->allocate(dev);
0071     if (err)
0072         phy->ops = NULL;
0073 
0074     return err;
0075 }
0076 
0077 void b43_phy_free(struct b43_wldev *dev)
0078 {
0079     dev->phy.ops->free(dev);
0080     dev->phy.ops = NULL;
0081 }
0082 
0083 int b43_phy_init(struct b43_wldev *dev)
0084 {
0085     struct b43_phy *phy = &dev->phy;
0086     const struct b43_phy_operations *ops = phy->ops;
0087     int err;
0088 
0089     /* During PHY init we need to use some channel. On the first init this
0090      * function is called *before* b43_op_config, so our pointer is NULL.
0091      */
0092     if (!phy->chandef) {
0093         phy->chandef = &dev->wl->hw->conf.chandef;
0094         phy->channel = phy->chandef->chan->hw_value;
0095     }
0096 
0097     phy->ops->switch_analog(dev, true);
0098     b43_software_rfkill(dev, false);
0099 
0100     err = ops->init(dev);
0101     if (err) {
0102         b43err(dev->wl, "PHY init failed\n");
0103         goto err_block_rf;
0104     }
0105     phy->do_full_init = false;
0106 
0107     err = b43_switch_channel(dev, phy->channel);
0108     if (err) {
0109         b43err(dev->wl, "PHY init: Channel switch to default failed\n");
0110         goto err_phy_exit;
0111     }
0112 
0113     return 0;
0114 
0115 err_phy_exit:
0116     phy->do_full_init = true;
0117     if (ops->exit)
0118         ops->exit(dev);
0119 err_block_rf:
0120     b43_software_rfkill(dev, true);
0121 
0122     return err;
0123 }
0124 
0125 void b43_phy_exit(struct b43_wldev *dev)
0126 {
0127     const struct b43_phy_operations *ops = dev->phy.ops;
0128 
0129     b43_software_rfkill(dev, true);
0130     dev->phy.do_full_init = true;
0131     if (ops->exit)
0132         ops->exit(dev);
0133 }
0134 
0135 bool b43_has_hardware_pctl(struct b43_wldev *dev)
0136 {
0137     if (!dev->phy.hardware_power_control)
0138         return false;
0139     if (!dev->phy.ops->supports_hwpctl)
0140         return false;
0141     return dev->phy.ops->supports_hwpctl(dev);
0142 }
0143 
0144 void b43_radio_lock(struct b43_wldev *dev)
0145 {
0146     u32 macctl;
0147 
0148 #if B43_DEBUG
0149     B43_WARN_ON(dev->phy.radio_locked);
0150     dev->phy.radio_locked = true;
0151 #endif
0152 
0153     macctl = b43_read32(dev, B43_MMIO_MACCTL);
0154     macctl |= B43_MACCTL_RADIOLOCK;
0155     b43_write32(dev, B43_MMIO_MACCTL, macctl);
0156     /* Commit the write and wait for the firmware
0157      * to finish any radio register access. */
0158     b43_read32(dev, B43_MMIO_MACCTL);
0159     udelay(10);
0160 }
0161 
0162 void b43_radio_unlock(struct b43_wldev *dev)
0163 {
0164     u32 macctl;
0165 
0166 #if B43_DEBUG
0167     B43_WARN_ON(!dev->phy.radio_locked);
0168     dev->phy.radio_locked = false;
0169 #endif
0170 
0171     /* Commit any write */
0172     b43_read16(dev, B43_MMIO_PHY_VER);
0173     /* unlock */
0174     macctl = b43_read32(dev, B43_MMIO_MACCTL);
0175     macctl &= ~B43_MACCTL_RADIOLOCK;
0176     b43_write32(dev, B43_MMIO_MACCTL, macctl);
0177 }
0178 
0179 void b43_phy_lock(struct b43_wldev *dev)
0180 {
0181 #if B43_DEBUG
0182     B43_WARN_ON(dev->phy.phy_locked);
0183     dev->phy.phy_locked = true;
0184 #endif
0185     B43_WARN_ON(dev->dev->core_rev < 3);
0186 
0187     if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
0188         b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
0189 }
0190 
0191 void b43_phy_unlock(struct b43_wldev *dev)
0192 {
0193 #if B43_DEBUG
0194     B43_WARN_ON(!dev->phy.phy_locked);
0195     dev->phy.phy_locked = false;
0196 #endif
0197     B43_WARN_ON(dev->dev->core_rev < 3);
0198 
0199     if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
0200         b43_power_saving_ctl_bits(dev, 0);
0201 }
0202 
0203 static inline void assert_mac_suspended(struct b43_wldev *dev)
0204 {
0205     if (!B43_DEBUG)
0206         return;
0207     if ((b43_status(dev) >= B43_STAT_INITIALIZED) &&
0208         (dev->mac_suspended <= 0)) {
0209         b43dbg(dev->wl, "PHY/RADIO register access with "
0210                "enabled MAC.\n");
0211         dump_stack();
0212     }
0213 }
0214 
0215 u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
0216 {
0217     assert_mac_suspended(dev);
0218     dev->phy.writes_counter = 0;
0219     return dev->phy.ops->radio_read(dev, reg);
0220 }
0221 
0222 void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
0223 {
0224     assert_mac_suspended(dev);
0225     if (b43_bus_host_is_pci(dev->dev) &&
0226         ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
0227         b43_read32(dev, B43_MMIO_MACCTL);
0228         dev->phy.writes_counter = 1;
0229     }
0230     dev->phy.ops->radio_write(dev, reg, value);
0231 }
0232 
0233 void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
0234 {
0235     b43_radio_write16(dev, offset,
0236               b43_radio_read16(dev, offset) & mask);
0237 }
0238 
0239 void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
0240 {
0241     b43_radio_write16(dev, offset,
0242               b43_radio_read16(dev, offset) | set);
0243 }
0244 
0245 void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
0246 {
0247     b43_radio_write16(dev, offset,
0248               (b43_radio_read16(dev, offset) & mask) | set);
0249 }
0250 
0251 bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask,
0252               u16 value, int delay, int timeout)
0253 {
0254     u16 val;
0255     int i;
0256 
0257     for (i = 0; i < timeout; i += delay) {
0258         val = b43_radio_read(dev, offset);
0259         if ((val & mask) == value)
0260             return true;
0261         udelay(delay);
0262     }
0263     return false;
0264 }
0265 
0266 u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
0267 {
0268     assert_mac_suspended(dev);
0269     dev->phy.writes_counter = 0;
0270 
0271     if (dev->phy.ops->phy_read)
0272         return dev->phy.ops->phy_read(dev, reg);
0273 
0274     b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
0275     return b43_read16(dev, B43_MMIO_PHY_DATA);
0276 }
0277 
0278 void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
0279 {
0280     assert_mac_suspended(dev);
0281     if (b43_bus_host_is_pci(dev->dev) &&
0282         ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
0283         b43_read16(dev, B43_MMIO_PHY_VER);
0284         dev->phy.writes_counter = 1;
0285     }
0286 
0287     if (dev->phy.ops->phy_write)
0288         return dev->phy.ops->phy_write(dev, reg, value);
0289 
0290     b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
0291     b43_write16(dev, B43_MMIO_PHY_DATA, value);
0292 }
0293 
0294 void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
0295 {
0296     b43_phy_write(dev, destreg, b43_phy_read(dev, srcreg));
0297 }
0298 
0299 void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
0300 {
0301     if (dev->phy.ops->phy_maskset) {
0302         assert_mac_suspended(dev);
0303         dev->phy.ops->phy_maskset(dev, offset, mask, 0);
0304     } else {
0305         b43_phy_write(dev, offset,
0306                   b43_phy_read(dev, offset) & mask);
0307     }
0308 }
0309 
0310 void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
0311 {
0312     if (dev->phy.ops->phy_maskset) {
0313         assert_mac_suspended(dev);
0314         dev->phy.ops->phy_maskset(dev, offset, 0xFFFF, set);
0315     } else {
0316         b43_phy_write(dev, offset,
0317                   b43_phy_read(dev, offset) | set);
0318     }
0319 }
0320 
0321 void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
0322 {
0323     if (dev->phy.ops->phy_maskset) {
0324         assert_mac_suspended(dev);
0325         dev->phy.ops->phy_maskset(dev, offset, mask, set);
0326     } else {
0327         b43_phy_write(dev, offset,
0328                   (b43_phy_read(dev, offset) & mask) | set);
0329     }
0330 }
0331 
0332 void b43_phy_put_into_reset(struct b43_wldev *dev)
0333 {
0334     u32 tmp;
0335 
0336     switch (dev->dev->bus_type) {
0337 #ifdef CONFIG_B43_BCMA
0338     case B43_BUS_BCMA:
0339         tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
0340         tmp &= ~B43_BCMA_IOCTL_GMODE;
0341         tmp |= B43_BCMA_IOCTL_PHY_RESET;
0342         tmp |= BCMA_IOCTL_FGC;
0343         bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
0344         udelay(1);
0345 
0346         tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
0347         tmp &= ~BCMA_IOCTL_FGC;
0348         bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
0349         udelay(1);
0350         break;
0351 #endif
0352 #ifdef CONFIG_B43_SSB
0353     case B43_BUS_SSB:
0354         tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
0355         tmp &= ~B43_TMSLOW_GMODE;
0356         tmp |= B43_TMSLOW_PHYRESET;
0357         tmp |= SSB_TMSLOW_FGC;
0358         ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
0359         usleep_range(1000, 2000);
0360 
0361         tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
0362         tmp &= ~SSB_TMSLOW_FGC;
0363         ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
0364         usleep_range(1000, 2000);
0365 
0366         break;
0367 #endif
0368     }
0369 }
0370 
0371 void b43_phy_take_out_of_reset(struct b43_wldev *dev)
0372 {
0373     u32 tmp;
0374 
0375     switch (dev->dev->bus_type) {
0376 #ifdef CONFIG_B43_BCMA
0377     case B43_BUS_BCMA:
0378         /* Unset reset bit (with forcing clock) */
0379         tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
0380         tmp &= ~B43_BCMA_IOCTL_PHY_RESET;
0381         tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN;
0382         tmp |= BCMA_IOCTL_FGC;
0383         bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
0384         udelay(1);
0385 
0386         /* Do not force clock anymore */
0387         tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
0388         tmp &= ~BCMA_IOCTL_FGC;
0389         tmp |= B43_BCMA_IOCTL_PHY_CLKEN;
0390         bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
0391         udelay(1);
0392         break;
0393 #endif
0394 #ifdef CONFIG_B43_SSB
0395     case B43_BUS_SSB:
0396         /* Unset reset bit (with forcing clock) */
0397         tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
0398         tmp &= ~B43_TMSLOW_PHYRESET;
0399         tmp &= ~B43_TMSLOW_PHYCLKEN;
0400         tmp |= SSB_TMSLOW_FGC;
0401         ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
0402         ssb_read32(dev->dev->sdev, SSB_TMSLOW); /* flush */
0403         usleep_range(1000, 2000);
0404 
0405         tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
0406         tmp &= ~SSB_TMSLOW_FGC;
0407         tmp |= B43_TMSLOW_PHYCLKEN;
0408         ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
0409         ssb_read32(dev->dev->sdev, SSB_TMSLOW); /* flush */
0410         usleep_range(1000, 2000);
0411         break;
0412 #endif
0413     }
0414 }
0415 
0416 int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
0417 {
0418     struct b43_phy *phy = &(dev->phy);
0419     u16 channelcookie, savedcookie;
0420     int err;
0421 
0422     /* First we set the channel radio code to prevent the
0423      * firmware from sending ghost packets.
0424      */
0425     channelcookie = new_channel;
0426     if (b43_current_band(dev->wl) == NL80211_BAND_5GHZ)
0427         channelcookie |= B43_SHM_SH_CHAN_5GHZ;
0428     /* FIXME: set 40Mhz flag if required */
0429     if (0)
0430         channelcookie |= B43_SHM_SH_CHAN_40MHZ;
0431     savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
0432     b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
0433 
0434     /* Now try to switch the PHY hardware channel. */
0435     err = phy->ops->switch_channel(dev, new_channel);
0436     if (err)
0437         goto err_restore_cookie;
0438 
0439     /* Wait for the radio to tune to the channel and stabilize. */
0440     msleep(8);
0441 
0442     return 0;
0443 
0444 err_restore_cookie:
0445     b43_shm_write16(dev, B43_SHM_SHARED,
0446             B43_SHM_SH_CHAN, savedcookie);
0447 
0448     return err;
0449 }
0450 
0451 void b43_software_rfkill(struct b43_wldev *dev, bool blocked)
0452 {
0453     struct b43_phy *phy = &dev->phy;
0454 
0455     b43_mac_suspend(dev);
0456     phy->ops->software_rfkill(dev, blocked);
0457     phy->radio_on = !blocked;
0458     b43_mac_enable(dev);
0459 }
0460 
0461 /*
0462  * b43_phy_txpower_adjust_work - TX power workqueue.
0463  *
0464  * Workqueue for updating the TX power parameters in hardware.
0465  */
0466 void b43_phy_txpower_adjust_work(struct work_struct *work)
0467 {
0468     struct b43_wl *wl = container_of(work, struct b43_wl,
0469                      txpower_adjust_work);
0470     struct b43_wldev *dev;
0471 
0472     mutex_lock(&wl->mutex);
0473     dev = wl->current_dev;
0474 
0475     if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED)))
0476         dev->phy.ops->adjust_txpower(dev);
0477 
0478     mutex_unlock(&wl->mutex);
0479 }
0480 
0481 void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
0482 {
0483     struct b43_phy *phy = &dev->phy;
0484     unsigned long now = jiffies;
0485     enum b43_txpwr_result result;
0486 
0487     if (!(flags & B43_TXPWR_IGNORE_TIME)) {
0488         /* Check if it's time for a TXpower check. */
0489         if (time_before(now, phy->next_txpwr_check_time))
0490             return; /* Not yet */
0491     }
0492     /* The next check will be needed in two seconds, or later. */
0493     phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
0494 
0495     if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) &&
0496         (dev->dev->board_type == SSB_BOARD_BU4306))
0497         return; /* No software txpower adjustment needed */
0498 
0499     result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
0500     if (result == B43_TXPWR_RES_DONE)
0501         return; /* We are done. */
0502     B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST);
0503     B43_WARN_ON(phy->ops->adjust_txpower == NULL);
0504 
0505     /* We must adjust the transmission power in hardware.
0506      * Schedule b43_phy_txpower_adjust_work(). */
0507     ieee80211_queue_work(dev->wl->hw, &dev->wl->txpower_adjust_work);
0508 }
0509 
0510 int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
0511 {
0512     const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK);
0513     unsigned int a, b, c, d;
0514     unsigned int average;
0515     u32 tmp;
0516 
0517     tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset);
0518     a = tmp & 0xFF;
0519     b = (tmp >> 8) & 0xFF;
0520     c = (tmp >> 16) & 0xFF;
0521     d = (tmp >> 24) & 0xFF;
0522     if (a == 0 || a == B43_TSSI_MAX ||
0523         b == 0 || b == B43_TSSI_MAX ||
0524         c == 0 || c == B43_TSSI_MAX ||
0525         d == 0 || d == B43_TSSI_MAX)
0526         return -ENOENT;
0527     /* The values are OK. Clear them. */
0528     tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) |
0529           (B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24);
0530     b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp);
0531 
0532     if (is_ofdm) {
0533         a = (a + 32) & 0x3F;
0534         b = (b + 32) & 0x3F;
0535         c = (c + 32) & 0x3F;
0536         d = (d + 32) & 0x3F;
0537     }
0538 
0539     /* Get the average of the values with 0.5 added to each value. */
0540     average = (a + b + c + d + 2) / 4;
0541     if (is_ofdm) {
0542         /* Adjust for CCK-boost */
0543         if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1)
0544             & B43_HF_CCKBOOST)
0545             average = (average >= 13) ? (average - 13) : 0;
0546     }
0547 
0548     return average;
0549 }
0550 
0551 void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)
0552 {
0553     b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
0554 }
0555 
0556 
0557 bool b43_is_40mhz(struct b43_wldev *dev)
0558 {
0559     return dev->phy.chandef->width == NL80211_CHAN_WIDTH_40;
0560 }
0561 
0562 /* https://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
0563 void b43_phy_force_clock(struct b43_wldev *dev, bool force)
0564 {
0565     u32 tmp;
0566 
0567     WARN_ON(dev->phy.type != B43_PHYTYPE_N &&
0568         dev->phy.type != B43_PHYTYPE_HT &&
0569         dev->phy.type != B43_PHYTYPE_AC);
0570 
0571     switch (dev->dev->bus_type) {
0572 #ifdef CONFIG_B43_BCMA
0573     case B43_BUS_BCMA:
0574         tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
0575         if (force)
0576             tmp |= BCMA_IOCTL_FGC;
0577         else
0578             tmp &= ~BCMA_IOCTL_FGC;
0579         bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
0580         break;
0581 #endif
0582 #ifdef CONFIG_B43_SSB
0583     case B43_BUS_SSB:
0584         tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
0585         if (force)
0586             tmp |= SSB_TMSLOW_FGC;
0587         else
0588             tmp &= ~SSB_TMSLOW_FGC;
0589         ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
0590         break;
0591 #endif
0592     }
0593 }