18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Broadcom specific AMBA 38c2ecf20Sopenharmony_ci * ChipCommon core driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2005, Broadcom Corporation 68c2ecf20Sopenharmony_ci * Copyright 2006, 2007, Michael Buesch <m@bues.ch> 78c2ecf20Sopenharmony_ci * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "bcma_private.h" 138c2ecf20Sopenharmony_ci#include <linux/bcm47xx_wdt.h> 148c2ecf20Sopenharmony_ci#include <linux/export.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/bcma/bcma.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, 198c2ecf20Sopenharmony_ci u32 mask, u32 value) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci value &= mask; 228c2ecf20Sopenharmony_ci value |= bcma_cc_read32(cc, offset) & ~mask; 238c2ecf20Sopenharmony_ci bcma_cc_write32(cc, offset, value); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return value; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciu32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) 318c2ecf20Sopenharmony_ci return bcma_pmu_get_alp_clock(cc); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci return 20000000; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_get_alp_clock); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic bool bcma_core_cc_has_pmu_watchdog(struct bcma_drv_cc *cc) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) { 428c2ecf20Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53573) { 438c2ecf20Sopenharmony_ci WARN(bus->chipinfo.rev <= 1, "No watchdog available\n"); 448c2ecf20Sopenharmony_ci /* 53573B0 and 53573B1 have bugged PMU watchdog. It can 458c2ecf20Sopenharmony_ci * be enabled but timer can't be bumped. Use CC one 468c2ecf20Sopenharmony_ci * instead. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci return false; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci return true; 518c2ecf20Sopenharmony_ci } else { 528c2ecf20Sopenharmony_ci return false; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 598c2ecf20Sopenharmony_ci u32 nb; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (bcma_core_cc_has_pmu_watchdog(cc)) { 628c2ecf20Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) 638c2ecf20Sopenharmony_ci nb = 32; 648c2ecf20Sopenharmony_ci else if (cc->core->id.rev < 26) 658c2ecf20Sopenharmony_ci nb = 16; 668c2ecf20Sopenharmony_ci else 678c2ecf20Sopenharmony_ci nb = (cc->core->id.rev >= 37) ? 32 : 24; 688c2ecf20Sopenharmony_ci } else { 698c2ecf20Sopenharmony_ci nb = 28; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci if (nb == 32) 728c2ecf20Sopenharmony_ci return 0xffffffff; 738c2ecf20Sopenharmony_ci else 748c2ecf20Sopenharmony_ci return (1 << nb) - 1; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic u32 bcma_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, 788c2ecf20Sopenharmony_ci u32 ticks) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return bcma_chipco_watchdog_timer_set(cc, ticks); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic u32 bcma_chipco_watchdog_timer_set_ms_wdt(struct bcm47xx_wdt *wdt, 868c2ecf20Sopenharmony_ci u32 ms) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt); 898c2ecf20Sopenharmony_ci u32 ticks; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ticks = bcma_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms); 928c2ecf20Sopenharmony_ci return ticks / cc->ticks_per_ms; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) { 1008c2ecf20Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) 1018c2ecf20Sopenharmony_ci /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP 1028c2ecf20Sopenharmony_ci * clock 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci return bcma_chipco_get_alp_clock(cc) / 4000; 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci /* based on 32KHz ILP clock */ 1078c2ecf20Sopenharmony_ci return 32; 1088c2ecf20Sopenharmony_ci } else { 1098c2ecf20Sopenharmony_ci return bcma_chipco_get_alp_clock(cc) / 1000; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciint bcma_chipco_watchdog_register(struct bcma_drv_cc *cc) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 1168c2ecf20Sopenharmony_ci struct bcm47xx_wdt wdt = {}; 1178c2ecf20Sopenharmony_ci struct platform_device *pdev; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53573 && 1208c2ecf20Sopenharmony_ci bus->chipinfo.rev <= 1) { 1218c2ecf20Sopenharmony_ci pr_debug("No watchdog on 53573A0 / 53573A1\n"); 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci wdt.driver_data = cc; 1268c2ecf20Sopenharmony_ci wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt; 1278c2ecf20Sopenharmony_ci wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt; 1288c2ecf20Sopenharmony_ci wdt.max_timer_ms = 1298c2ecf20Sopenharmony_ci bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci pdev = platform_device_register_data(NULL, "bcm47xx-wdt", 1328c2ecf20Sopenharmony_ci bus->num, &wdt, 1338c2ecf20Sopenharmony_ci sizeof(wdt)); 1348c2ecf20Sopenharmony_ci if (IS_ERR(pdev)) 1358c2ecf20Sopenharmony_ci return PTR_ERR(pdev); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci cc->watchdog = pdev; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci switch (cc->capabilities & BCMA_CC_CAP_FLASHT) { 1478c2ecf20Sopenharmony_ci case BCMA_CC_FLASHT_STSER: 1488c2ecf20Sopenharmony_ci case BCMA_CC_FLASHT_ATSER: 1498c2ecf20Sopenharmony_ci bcma_debug(bus, "Found serial flash\n"); 1508c2ecf20Sopenharmony_ci bcma_sflash_init(cc); 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case BCMA_CC_FLASHT_PARA: 1538c2ecf20Sopenharmony_ci bcma_debug(bus, "Found parallel flash\n"); 1548c2ecf20Sopenharmony_ci bcma_pflash_init(cc); 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci default: 1578c2ecf20Sopenharmony_ci bcma_err(bus, "Flash type not supported\n"); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (cc->core->id.rev == 38 || 1618c2ecf20Sopenharmony_ci bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { 1628c2ecf20Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_NFLASH) { 1638c2ecf20Sopenharmony_ci bcma_debug(bus, "Found NAND flash\n"); 1648c2ecf20Sopenharmony_ci bcma_nflash_init(cc); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_civoid bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (cc->early_setup_done) 1748c2ecf20Sopenharmony_ci return; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci spin_lock_init(&cc->gpio_lock); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (cc->core->id.rev >= 11) 1798c2ecf20Sopenharmony_ci cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); 1808c2ecf20Sopenharmony_ci cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); 1818c2ecf20Sopenharmony_ci if (cc->core->id.rev >= 35) 1828c2ecf20Sopenharmony_ci cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) 1858c2ecf20Sopenharmony_ci bcma_pmu_early_init(cc); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (bus->hosttype == BCMA_HOSTTYPE_SOC) 1888c2ecf20Sopenharmony_ci bcma_core_chipcommon_flash_detect(cc); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci cc->early_setup_done = true; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_civoid bcma_core_chipcommon_init(struct bcma_drv_cc *cc) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci u32 leddc_on = 10; 1968c2ecf20Sopenharmony_ci u32 leddc_off = 90; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (cc->setup_done) 1998c2ecf20Sopenharmony_ci return; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci bcma_core_chipcommon_early_init(cc); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (cc->core->id.rev >= 20) { 2048c2ecf20Sopenharmony_ci u32 pullup = 0, pulldown = 0; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM43142) { 2078c2ecf20Sopenharmony_ci pullup = 0x402e0; 2088c2ecf20Sopenharmony_ci pulldown = 0x20500; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, pullup); 2128c2ecf20Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, pulldown); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PMU) 2168c2ecf20Sopenharmony_ci bcma_pmu_init(cc); 2178c2ecf20Sopenharmony_ci if (cc->capabilities & BCMA_CC_CAP_PCTL) 2188c2ecf20Sopenharmony_ci bcma_err(cc->core->bus, "Power control not implemented!\n"); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (cc->core->id.rev >= 16) { 2218c2ecf20Sopenharmony_ci if (cc->core->bus->sprom.leddc_on_time && 2228c2ecf20Sopenharmony_ci cc->core->bus->sprom.leddc_off_time) { 2238c2ecf20Sopenharmony_ci leddc_on = cc->core->bus->sprom.leddc_on_time; 2248c2ecf20Sopenharmony_ci leddc_off = cc->core->bus->sprom.leddc_off_time; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_GPIOTIMER, 2278c2ecf20Sopenharmony_ci ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | 2288c2ecf20Sopenharmony_ci (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT))); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci cc->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci cc->setup_done = true; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ 2368c2ecf20Sopenharmony_ciu32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci u32 maxt; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci maxt = bcma_chipco_watchdog_get_max_timer(cc); 2418c2ecf20Sopenharmony_ci if (bcma_core_cc_has_pmu_watchdog(cc)) { 2428c2ecf20Sopenharmony_ci if (ticks == 1) 2438c2ecf20Sopenharmony_ci ticks = 2; 2448c2ecf20Sopenharmony_ci else if (ticks > maxt) 2458c2ecf20Sopenharmony_ci ticks = maxt; 2468c2ecf20Sopenharmony_ci bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks); 2478c2ecf20Sopenharmony_ci } else { 2488c2ecf20Sopenharmony_ci struct bcma_bus *bus = cc->core->bus; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 && 2518c2ecf20Sopenharmony_ci bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 && 2528c2ecf20Sopenharmony_ci bus->chipinfo.id != BCMA_CHIP_ID_BCM53018) 2538c2ecf20Sopenharmony_ci bcma_core_set_clockmode(cc->core, 2548c2ecf20Sopenharmony_ci ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (ticks > maxt) 2578c2ecf20Sopenharmony_ci ticks = maxt; 2588c2ecf20Sopenharmony_ci /* instant NMI */ 2598c2ecf20Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci return ticks; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_civoid bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ciu32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ciu32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ciu32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci unsigned long flags; 2828c2ecf20Sopenharmony_ci u32 res; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 2858c2ecf20Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value); 2868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return res; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_gpio_out); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ciu32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci unsigned long flags; 2958c2ecf20Sopenharmony_ci u32 res; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 2988c2ecf20Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value); 2998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return res; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* 3068c2ecf20Sopenharmony_ci * If the bit is set to 0, chipcommon controlls this GPIO, 3078c2ecf20Sopenharmony_ci * if the bit is set to 1, it is used by some part of the chip and not our code. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ciu32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci unsigned long flags; 3128c2ecf20Sopenharmony_ci u32 res; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 3158c2ecf20Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value); 3168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return res; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_gpio_control); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciu32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci unsigned long flags; 3258c2ecf20Sopenharmony_ci u32 res; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 3288c2ecf20Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value); 3298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return res; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciu32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci unsigned long flags; 3378c2ecf20Sopenharmony_ci u32 res; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 3408c2ecf20Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); 3418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return res; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ciu32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci unsigned long flags; 3498c2ecf20Sopenharmony_ci u32 res; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (cc->core->id.rev < 20) 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 3558c2ecf20Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLUP, mask, value); 3568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return res; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ciu32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci unsigned long flags; 3648c2ecf20Sopenharmony_ci u32 res; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (cc->core->id.rev < 20) 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 3708c2ecf20Sopenharmony_ci res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLDOWN, mask, value); 3718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return res; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci#ifdef CONFIG_BCMA_DRIVER_MIPS 3778c2ecf20Sopenharmony_civoid bcma_chipco_serial_init(struct bcma_drv_cc *cc) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci unsigned int irq; 3808c2ecf20Sopenharmony_ci u32 baud_base; 3818c2ecf20Sopenharmony_ci u32 i; 3828c2ecf20Sopenharmony_ci unsigned int ccrev = cc->core->id.rev; 3838c2ecf20Sopenharmony_ci struct bcma_serial_port *ports = cc->serial_ports; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (ccrev >= 11 && ccrev != 15) { 3868c2ecf20Sopenharmony_ci baud_base = bcma_chipco_get_alp_clock(cc); 3878c2ecf20Sopenharmony_ci if (ccrev >= 21) { 3888c2ecf20Sopenharmony_ci /* Turn off UART clock before switching clocksource. */ 3898c2ecf20Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_CORECTL, 3908c2ecf20Sopenharmony_ci bcma_cc_read32(cc, BCMA_CC_CORECTL) 3918c2ecf20Sopenharmony_ci & ~BCMA_CC_CORECTL_UARTCLKEN); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci /* Set the override bit so we don't divide it */ 3948c2ecf20Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_CORECTL, 3958c2ecf20Sopenharmony_ci bcma_cc_read32(cc, BCMA_CC_CORECTL) 3968c2ecf20Sopenharmony_ci | BCMA_CC_CORECTL_UARTCLK0); 3978c2ecf20Sopenharmony_ci if (ccrev >= 21) { 3988c2ecf20Sopenharmony_ci /* Re-enable the UART clock. */ 3998c2ecf20Sopenharmony_ci bcma_cc_write32(cc, BCMA_CC_CORECTL, 4008c2ecf20Sopenharmony_ci bcma_cc_read32(cc, BCMA_CC_CORECTL) 4018c2ecf20Sopenharmony_ci | BCMA_CC_CORECTL_UARTCLKEN); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci } else { 4048c2ecf20Sopenharmony_ci bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", 4058c2ecf20Sopenharmony_ci ccrev); 4068c2ecf20Sopenharmony_ci return; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci irq = bcma_core_irq(cc->core, 0); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Determine the registers of the UARTs */ 4128c2ecf20Sopenharmony_ci cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART); 4138c2ecf20Sopenharmony_ci for (i = 0; i < cc->nr_serial_ports; i++) { 4148c2ecf20Sopenharmony_ci ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA + 4158c2ecf20Sopenharmony_ci (i * 256); 4168c2ecf20Sopenharmony_ci ports[i].irq = irq; 4178c2ecf20Sopenharmony_ci ports[i].baud_base = baud_base; 4188c2ecf20Sopenharmony_ci ports[i].reg_shift = 0; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci#endif /* CONFIG_BCMA_DRIVER_MIPS */ 422