162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Broadcom specific AMBA 362306a36Sopenharmony_ci * ChipCommon core driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2005, Broadcom Corporation 662306a36Sopenharmony_ci * Copyright 2006, 2007, Michael Buesch <m@bues.ch> 762306a36Sopenharmony_ci * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "bcma_private.h" 1362306a36Sopenharmony_ci#include <linux/bcm47xx_wdt.h> 1462306a36Sopenharmony_ci#include <linux/export.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/bcma/bcma.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, 1962306a36Sopenharmony_ci u32 mask, u32 value) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci value &= mask; 2262306a36Sopenharmony_ci value |= bcma_cc_read32(cc, offset) & ~mask; 2362306a36Sopenharmony_ci bcma_cc_write32(cc, offset, value); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci return value; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciu32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) 3162306a36Sopenharmony_ci return bcma_pmu_get_alp_clock(cc); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci return 20000000; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_get_alp_clock); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic bool bcma_core_cc_has_pmu_watchdog(struct bcma_drv_cc *cc) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) { 4262306a36Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53573) { 4362306a36Sopenharmony_ci WARN(bus->chipinfo.rev <= 1, "No watchdog available\n"); 4462306a36Sopenharmony_ci /* 53573B0 and 53573B1 have bugged PMU watchdog. It can 4562306a36Sopenharmony_ci * be enabled but timer can't be bumped. Use CC one 4662306a36Sopenharmony_ci * instead. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci return false; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci return true; 5162306a36Sopenharmony_ci } else { 5262306a36Sopenharmony_ci return false; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 5962306a36Sopenharmony_ci u32 nb; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (bcma_core_cc_has_pmu_watchdog(cc)) { 6262306a36Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) 6362306a36Sopenharmony_ci nb = 32; 6462306a36Sopenharmony_ci else if (cc->core->id.rev < 26) 6562306a36Sopenharmony_ci nb = 16; 6662306a36Sopenharmony_ci else 6762306a36Sopenharmony_ci nb = (cc->core->id.rev >= 37) ? 32 : 24; 6862306a36Sopenharmony_ci } else { 6962306a36Sopenharmony_ci nb = 28; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci if (nb == 32) 7262306a36Sopenharmony_ci return 0xffffffff; 7362306a36Sopenharmony_ci else 7462306a36Sopenharmony_ci return (1 << nb) - 1; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic u32 bcma_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, 7862306a36Sopenharmony_ci u32 ticks) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return bcma_chipco_watchdog_timer_set(cc, ticks); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic u32 bcma_chipco_watchdog_timer_set_ms_wdt(struct bcm47xx_wdt *wdt, 8662306a36Sopenharmony_ci u32 ms) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt); 8962306a36Sopenharmony_ci u32 ticks; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci ticks = bcma_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms); 9262306a36Sopenharmony_ci return ticks / cc->ticks_per_ms; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) { 10062306a36Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) 10162306a36Sopenharmony_ci /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP 10262306a36Sopenharmony_ci * clock 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci return bcma_chipco_get_alp_clock(cc) / 4000; 10562306a36Sopenharmony_ci else 10662306a36Sopenharmony_ci /* based on 32KHz ILP clock */ 10762306a36Sopenharmony_ci return 32; 10862306a36Sopenharmony_ci } else { 10962306a36Sopenharmony_ci return bcma_chipco_get_alp_clock(cc) / 1000; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciint bcma_chipco_watchdog_register(struct bcma_drv_cc *cc) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 11662306a36Sopenharmony_ci struct bcm47xx_wdt wdt = {}; 11762306a36Sopenharmony_ci struct platform_device *pdev; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53573 && 12062306a36Sopenharmony_ci bus->chipinfo.rev <= 1) { 12162306a36Sopenharmony_ci pr_debug("No watchdog on 53573A0 / 53573A1\n"); 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci wdt.driver_data = cc; 12662306a36Sopenharmony_ci wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt; 12762306a36Sopenharmony_ci wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt; 12862306a36Sopenharmony_ci wdt.max_timer_ms = 12962306a36Sopenharmony_ci bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci pdev = platform_device_register_data(NULL, "bcm47xx-wdt", 13262306a36Sopenharmony_ci bus->num, &wdt, 13362306a36Sopenharmony_ci sizeof(wdt)); 13462306a36Sopenharmony_ci if (IS_ERR(pdev)) 13562306a36Sopenharmony_ci return PTR_ERR(pdev); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci cc->watchdog = pdev; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { 14762306a36Sopenharmony_ci case BCMA_CC_FLASHT_STSER: 14862306a36Sopenharmony_ci case BCMA_CC_FLASHT_ATSER: 14962306a36Sopenharmony_ci bcma_debug(bus, "Found serial flash\n"); 15062306a36Sopenharmony_ci bcma_sflash_init(cc); 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci case BCMA_CC_FLASHT_PARA: 15362306a36Sopenharmony_ci bcma_debug(bus, "Found parallel flash\n"); 15462306a36Sopenharmony_ci bcma_pflash_init(cc); 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci default: 15762306a36Sopenharmony_ci bcma_err(bus, "Flash type not supported\n"); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (cc->core->id.rev == 38 || 16162306a36Sopenharmony_ci bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { 16262306a36Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_NFLASH) { 16362306a36Sopenharmony_ci bcma_debug(bus, "Found NAND flash\n"); 16462306a36Sopenharmony_ci bcma_nflash_init(cc); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_civoid bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (cc->early_setup_done) 17462306a36Sopenharmony_ci return; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci spin_lock_init(&cc->gpio_lock); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (cc->core->id.rev >= 11) 17962306a36Sopenharmony_ci cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); 18062306a36Sopenharmony_ci cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); 18162306a36Sopenharmony_ci if (cc->core->id.rev >= 35) 18262306a36Sopenharmony_ci cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) 18562306a36Sopenharmony_ci bcma_pmu_early_init(cc); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (bus->hosttype == BCMA_HOSTTYPE_SOC) 18862306a36Sopenharmony_ci bcma_core_chipcommon_flash_detect(cc); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci cc->early_setup_done = true; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_civoid bcma_core_chipcommon_init(struct bcma_drv_cc *cc) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci u32 leddc_on = 10; 19662306a36Sopenharmony_ci u32 leddc_off = 90; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (cc->setup_done) 19962306a36Sopenharmony_ci return; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci bcma_core_chipcommon_early_init(cc); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (cc->core->id.rev >= 20) { 20462306a36Sopenharmony_ci u32 pullup = 0, pulldown = 0; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM43142) { 20762306a36Sopenharmony_ci pullup = 0x402e0; 20862306a36Sopenharmony_ci pulldown = 0x20500; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, pullup); 21262306a36Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, pulldown); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) 21662306a36Sopenharmony_ci bcma_pmu_init(cc); 21762306a36Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PCTL) 21862306a36Sopenharmony_ci bcma_err(cc->core->bus, "Power control not implemented!\n"); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (cc->core->id.rev >= 16) { 22162306a36Sopenharmony_ci if (cc->core->bus->sprom.leddc_on_time && 22262306a36Sopenharmony_ci cc->core->bus->sprom.leddc_off_time) { 22362306a36Sopenharmony_ci leddc_on = cc->core->bus->sprom.leddc_on_time; 22462306a36Sopenharmony_ci leddc_off = cc->core->bus->sprom.leddc_off_time; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_GPIOTIMER, 22762306a36Sopenharmony_ci ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | 22862306a36Sopenharmony_ci (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci cc->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci cc->setup_done = true; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ 23662306a36Sopenharmony_ciu32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci u32 maxt; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci maxt = bcma_chipco_watchdog_get_max_timer(cc); 24162306a36Sopenharmony_ci if (bcma_core_cc_has_pmu_watchdog(cc)) { 24262306a36Sopenharmony_ci if (ticks == 1) 24362306a36Sopenharmony_ci ticks = 2; 24462306a36Sopenharmony_ci else if (ticks > maxt) 24562306a36Sopenharmony_ci ticks = maxt; 24662306a36Sopenharmony_ci bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks); 24762306a36Sopenharmony_ci } else { 24862306a36Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 && 25162306a36Sopenharmony_ci bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 && 25262306a36Sopenharmony_ci bus->chipinfo.id != BCMA_CHIP_ID_BCM53018) 25362306a36Sopenharmony_ci bcma_core_set_clockmode(cc->core, 25462306a36Sopenharmony_ci ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (ticks > maxt) 25762306a36Sopenharmony_ci ticks = maxt; 25862306a36Sopenharmony_ci /* instant NMI */ 25962306a36Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci return ticks; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_civoid bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ciu32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ciu32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciu32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci unsigned long flags; 28262306a36Sopenharmony_ci u32 res; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 28562306a36Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value); 28662306a36Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return res; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_gpio_out); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ciu32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci unsigned long flags; 29562306a36Sopenharmony_ci u32 res; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 29862306a36Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value); 29962306a36Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return res; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* 30662306a36Sopenharmony_ci * If the bit is set to 0, chipcommon controls this GPIO, 30762306a36Sopenharmony_ci * if the bit is set to 1, it is used by some part of the chip and not our code. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ciu32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci unsigned long flags; 31262306a36Sopenharmony_ci u32 res; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 31562306a36Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value); 31662306a36Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return res; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_gpio_control); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ciu32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci unsigned long flags; 32562306a36Sopenharmony_ci u32 res; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 32862306a36Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value); 32962306a36Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return res; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ciu32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci unsigned long flags; 33762306a36Sopenharmony_ci u32 res; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 34062306a36Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); 34162306a36Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return res; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ciu32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci unsigned long flags; 34962306a36Sopenharmony_ci u32 res; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (cc->core->id.rev < 20) 35262306a36Sopenharmony_ci return 0; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 35562306a36Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLUP, mask, value); 35662306a36Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return res; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ciu32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci unsigned long flags; 36462306a36Sopenharmony_ci u32 res; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (cc->core->id.rev < 20) 36762306a36Sopenharmony_ci return 0; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 37062306a36Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLDOWN, mask, value); 37162306a36Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return res; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci#ifdef CONFIG_BCMA_DRIVER_MIPS 37762306a36Sopenharmony_civoid bcma_chipco_serial_init(struct bcma_drv_cc *cc) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci unsigned int irq; 38062306a36Sopenharmony_ci u32 baud_base; 38162306a36Sopenharmony_ci u32 i; 38262306a36Sopenharmony_ci unsigned int ccrev = cc->core->id.rev; 38362306a36Sopenharmony_ci struct bcma_serial_port *ports = cc->serial_ports; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (ccrev >= 11 && ccrev != 15) { 38662306a36Sopenharmony_ci baud_base = bcma_chipco_get_alp_clock(cc); 38762306a36Sopenharmony_ci if (ccrev >= 21) { 38862306a36Sopenharmony_ci /* Turn off UART clock before switching clocksource. */ 38962306a36Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_CORECTL, 39062306a36Sopenharmony_ci bcma_cc_read32(cc, BCMA_CC_CORECTL) 39162306a36Sopenharmony_ci & ~BCMA_CC_CORECTL_UARTCLKEN); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci /* Set the override bit so we don't divide it */ 39462306a36Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_CORECTL, 39562306a36Sopenharmony_ci bcma_cc_read32(cc, BCMA_CC_CORECTL) 39662306a36Sopenharmony_ci | BCMA_CC_CORECTL_UARTCLK0); 39762306a36Sopenharmony_ci if (ccrev >= 21) { 39862306a36Sopenharmony_ci /* Re-enable the UART clock. */ 39962306a36Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_CORECTL, 40062306a36Sopenharmony_ci bcma_cc_read32(cc, BCMA_CC_CORECTL) 40162306a36Sopenharmony_ci | BCMA_CC_CORECTL_UARTCLKEN); 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } else { 40462306a36Sopenharmony_ci bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", 40562306a36Sopenharmony_ci ccrev); 40662306a36Sopenharmony_ci return; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci irq = bcma_core_irq(cc->core, 0); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Determine the registers of the UARTs */ 41262306a36Sopenharmony_ci cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); 41362306a36Sopenharmony_ci for (i = 0; i < cc->nr_serial_ports; i++) { 41462306a36Sopenharmony_ci ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA + 41562306a36Sopenharmony_ci (i * 256); 41662306a36Sopenharmony_ci ports[i].irq = irq; 41762306a36Sopenharmony_ci ports[i].baud_base = baud_base; 41862306a36Sopenharmony_ci ports[i].reg_shift = 0; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci#endif /* CONFIG_BCMA_DRIVER_MIPS */ 422