18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Sonics Silicon Backplane 38c2ecf20Sopenharmony_ci * Broadcom 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 "ssb_private.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/ssb/ssb.h> 158c2ecf20Sopenharmony_ci#include <linux/ssb/ssb_regs.h> 168c2ecf20Sopenharmony_ci#include <linux/export.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/bcm47xx_wdt.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Clock sources */ 228c2ecf20Sopenharmony_cienum ssb_clksrc { 238c2ecf20Sopenharmony_ci /* PCI clock */ 248c2ecf20Sopenharmony_ci SSB_CHIPCO_CLKSRC_PCI, 258c2ecf20Sopenharmony_ci /* Crystal slow clock oscillator */ 268c2ecf20Sopenharmony_ci SSB_CHIPCO_CLKSRC_XTALOS, 278c2ecf20Sopenharmony_ci /* Low power oscillator */ 288c2ecf20Sopenharmony_ci SSB_CHIPCO_CLKSRC_LOPWROS, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, 338c2ecf20Sopenharmony_ci u32 mask, u32 value) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci value &= mask; 368c2ecf20Sopenharmony_ci value |= chipco_read32(cc, offset) & ~mask; 378c2ecf20Sopenharmony_ci chipco_write32(cc, offset, value); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci return value; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_civoid ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, 438c2ecf20Sopenharmony_ci enum ssb_clkmode mode) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct ssb_device *ccdev = cc->dev; 468c2ecf20Sopenharmony_ci struct ssb_bus *bus; 478c2ecf20Sopenharmony_ci u32 tmp; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (!ccdev) 508c2ecf20Sopenharmony_ci return; 518c2ecf20Sopenharmony_ci bus = ccdev->bus; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* We support SLOW only on 6..9 */ 548c2ecf20Sopenharmony_ci if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW) 558c2ecf20Sopenharmony_ci mode = SSB_CLKMODE_DYNAMIC; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (cc->capabilities & SSB_CHIPCO_CAP_PMU) 588c2ecf20Sopenharmony_ci return; /* PMU controls clockmode, separated function needed */ 598c2ecf20Sopenharmony_ci WARN_ON(ccdev->id.revision >= 20); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* chipcommon cores prior to rev6 don't support dynamic clock control */ 628c2ecf20Sopenharmony_ci if (ccdev->id.revision < 6) 638c2ecf20Sopenharmony_ci return; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* ChipCommon cores rev10+ need testing */ 668c2ecf20Sopenharmony_ci if (ccdev->id.revision >= 10) 678c2ecf20Sopenharmony_ci return; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci switch (mode) { 738c2ecf20Sopenharmony_ci case SSB_CLKMODE_SLOW: /* For revs 6..9 only */ 748c2ecf20Sopenharmony_ci tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); 758c2ecf20Sopenharmony_ci tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; 768c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci case SSB_CLKMODE_FAST: 798c2ecf20Sopenharmony_ci if (ccdev->id.revision < 10) { 808c2ecf20Sopenharmony_ci ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ 818c2ecf20Sopenharmony_ci tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); 828c2ecf20Sopenharmony_ci tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; 838c2ecf20Sopenharmony_ci tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; 848c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); 858c2ecf20Sopenharmony_ci } else { 868c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, 878c2ecf20Sopenharmony_ci (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) | 888c2ecf20Sopenharmony_ci SSB_CHIPCO_SYSCLKCTL_FORCEHT)); 898c2ecf20Sopenharmony_ci /* udelay(150); TODO: not available in early init */ 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci case SSB_CLKMODE_DYNAMIC: 938c2ecf20Sopenharmony_ci if (ccdev->id.revision < 10) { 948c2ecf20Sopenharmony_ci tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); 958c2ecf20Sopenharmony_ci tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; 968c2ecf20Sopenharmony_ci tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; 978c2ecf20Sopenharmony_ci tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; 988c2ecf20Sopenharmony_ci if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != 998c2ecf20Sopenharmony_ci SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) 1008c2ecf20Sopenharmony_ci tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; 1018c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* For dynamic control, we have to release our xtal_pu 1048c2ecf20Sopenharmony_ci * "force on" */ 1058c2ecf20Sopenharmony_ci if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) 1068c2ecf20Sopenharmony_ci ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); 1078c2ecf20Sopenharmony_ci } else { 1088c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, 1098c2ecf20Sopenharmony_ci (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & 1108c2ecf20Sopenharmony_ci ~SSB_CHIPCO_SYSCLKCTL_FORCEHT)); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci default: 1148c2ecf20Sopenharmony_ci WARN_ON(1); 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Get the Slow Clock Source */ 1198c2ecf20Sopenharmony_cistatic enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct ssb_bus *bus = cc->dev->bus; 1228c2ecf20Sopenharmony_ci u32 tmp; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (cc->dev->id.revision < 6) { 1258c2ecf20Sopenharmony_ci if (bus->bustype == SSB_BUSTYPE_SSB || 1268c2ecf20Sopenharmony_ci bus->bustype == SSB_BUSTYPE_PCMCIA) 1278c2ecf20Sopenharmony_ci return SSB_CHIPCO_CLKSRC_XTALOS; 1288c2ecf20Sopenharmony_ci if (bus->bustype == SSB_BUSTYPE_PCI) { 1298c2ecf20Sopenharmony_ci pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp); 1308c2ecf20Sopenharmony_ci if (tmp & 0x10) 1318c2ecf20Sopenharmony_ci return SSB_CHIPCO_CLKSRC_PCI; 1328c2ecf20Sopenharmony_ci return SSB_CHIPCO_CLKSRC_XTALOS; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci if (cc->dev->id.revision < 10) { 1368c2ecf20Sopenharmony_ci tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); 1378c2ecf20Sopenharmony_ci tmp &= 0x7; 1388c2ecf20Sopenharmony_ci if (tmp == 0) 1398c2ecf20Sopenharmony_ci return SSB_CHIPCO_CLKSRC_LOPWROS; 1408c2ecf20Sopenharmony_ci if (tmp == 1) 1418c2ecf20Sopenharmony_ci return SSB_CHIPCO_CLKSRC_XTALOS; 1428c2ecf20Sopenharmony_ci if (tmp == 2) 1438c2ecf20Sopenharmony_ci return SSB_CHIPCO_CLKSRC_PCI; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return SSB_CHIPCO_CLKSRC_XTALOS; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci/* Get maximum or minimum (depending on get_max flag) slowclock frequency. */ 1508c2ecf20Sopenharmony_cistatic int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci int limit; 1538c2ecf20Sopenharmony_ci enum ssb_clksrc clocksrc; 1548c2ecf20Sopenharmony_ci int divisor = 1; 1558c2ecf20Sopenharmony_ci u32 tmp; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci clocksrc = chipco_pctl_get_slowclksrc(cc); 1588c2ecf20Sopenharmony_ci if (cc->dev->id.revision < 6) { 1598c2ecf20Sopenharmony_ci switch (clocksrc) { 1608c2ecf20Sopenharmony_ci case SSB_CHIPCO_CLKSRC_PCI: 1618c2ecf20Sopenharmony_ci divisor = 64; 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci case SSB_CHIPCO_CLKSRC_XTALOS: 1648c2ecf20Sopenharmony_ci divisor = 32; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci default: 1678c2ecf20Sopenharmony_ci WARN_ON(1); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } else if (cc->dev->id.revision < 10) { 1708c2ecf20Sopenharmony_ci switch (clocksrc) { 1718c2ecf20Sopenharmony_ci case SSB_CHIPCO_CLKSRC_LOPWROS: 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case SSB_CHIPCO_CLKSRC_XTALOS: 1748c2ecf20Sopenharmony_ci case SSB_CHIPCO_CLKSRC_PCI: 1758c2ecf20Sopenharmony_ci tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); 1768c2ecf20Sopenharmony_ci divisor = (tmp >> 16) + 1; 1778c2ecf20Sopenharmony_ci divisor *= 4; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci } else { 1818c2ecf20Sopenharmony_ci tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL); 1828c2ecf20Sopenharmony_ci divisor = (tmp >> 16) + 1; 1838c2ecf20Sopenharmony_ci divisor *= 4; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci switch (clocksrc) { 1878c2ecf20Sopenharmony_ci case SSB_CHIPCO_CLKSRC_LOPWROS: 1888c2ecf20Sopenharmony_ci if (get_max) 1898c2ecf20Sopenharmony_ci limit = 43000; 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci limit = 25000; 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci case SSB_CHIPCO_CLKSRC_XTALOS: 1948c2ecf20Sopenharmony_ci if (get_max) 1958c2ecf20Sopenharmony_ci limit = 20200000; 1968c2ecf20Sopenharmony_ci else 1978c2ecf20Sopenharmony_ci limit = 19800000; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case SSB_CHIPCO_CLKSRC_PCI: 2008c2ecf20Sopenharmony_ci if (get_max) 2018c2ecf20Sopenharmony_ci limit = 34000000; 2028c2ecf20Sopenharmony_ci else 2038c2ecf20Sopenharmony_ci limit = 25000000; 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci limit /= divisor; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return limit; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void chipco_powercontrol_init(struct ssb_chipcommon *cc) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct ssb_bus *bus = cc->dev->bus; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (bus->chip_id == 0x4321) { 2168c2ecf20Sopenharmony_ci if (bus->chip_rev == 0) 2178c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4); 2188c2ecf20Sopenharmony_ci else if (bus->chip_rev == 1) 2198c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) 2238c2ecf20Sopenharmony_ci return; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (cc->dev->id.revision >= 10) { 2268c2ecf20Sopenharmony_ci /* Set Idle Power clock rate to 1Mhz */ 2278c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, 2288c2ecf20Sopenharmony_ci (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & 2298c2ecf20Sopenharmony_ci 0x0000FFFF) | 0x00040000); 2308c2ecf20Sopenharmony_ci } else { 2318c2ecf20Sopenharmony_ci int maxfreq; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci maxfreq = chipco_pctl_clockfreqlimit(cc, 1); 2348c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_PLLONDELAY, 2358c2ecf20Sopenharmony_ci (maxfreq * 150 + 999999) / 1000000); 2368c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY, 2378c2ecf20Sopenharmony_ci (maxfreq * 15 + 999999) / 1000000); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* https://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */ 2428c2ecf20Sopenharmony_cistatic u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct ssb_bus *bus = cc->dev->bus; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci switch (bus->chip_id) { 2478c2ecf20Sopenharmony_ci case 0x4312: 2488c2ecf20Sopenharmony_ci case 0x4322: 2498c2ecf20Sopenharmony_ci case 0x4328: 2508c2ecf20Sopenharmony_ci return 7000; 2518c2ecf20Sopenharmony_ci case 0x4325: 2528c2ecf20Sopenharmony_ci /* TODO: */ 2538c2ecf20Sopenharmony_ci default: 2548c2ecf20Sopenharmony_ci return 15000; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/* https://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */ 2598c2ecf20Sopenharmony_cistatic void calc_fast_powerup_delay(struct ssb_chipcommon *cc) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct ssb_bus *bus = cc->dev->bus; 2628c2ecf20Sopenharmony_ci int minfreq; 2638c2ecf20Sopenharmony_ci unsigned int tmp; 2648c2ecf20Sopenharmony_ci u32 pll_on_delay; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (bus->bustype != SSB_BUSTYPE_PCI) 2678c2ecf20Sopenharmony_ci return; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { 2708c2ecf20Sopenharmony_ci cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc); 2718c2ecf20Sopenharmony_ci return; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) 2758c2ecf20Sopenharmony_ci return; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci minfreq = chipco_pctl_clockfreqlimit(cc, 0); 2788c2ecf20Sopenharmony_ci pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY); 2798c2ecf20Sopenharmony_ci tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; 2808c2ecf20Sopenharmony_ci WARN_ON(tmp & ~0xFFFF); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci cc->fast_pwrup_delay = tmp; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic u32 ssb_chipco_alp_clock(struct ssb_chipcommon *cc) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci if (cc->capabilities & SSB_CHIPCO_CAP_PMU) 2888c2ecf20Sopenharmony_ci return ssb_pmu_get_alp_clock(cc); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return 20000000; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic u32 ssb_chipco_watchdog_get_max_timer(struct ssb_chipcommon *cc) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci u32 nb; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { 2988c2ecf20Sopenharmony_ci if (cc->dev->id.revision < 26) 2998c2ecf20Sopenharmony_ci nb = 16; 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci nb = (cc->dev->id.revision >= 37) ? 32 : 24; 3028c2ecf20Sopenharmony_ci } else { 3038c2ecf20Sopenharmony_ci nb = 28; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci if (nb == 32) 3068c2ecf20Sopenharmony_ci return 0xffffffff; 3078c2ecf20Sopenharmony_ci else 3088c2ecf20Sopenharmony_ci return (1 << nb) - 1; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ciu32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return ssb_chipco_watchdog_timer_set(cc, ticks); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ciu32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt); 3248c2ecf20Sopenharmony_ci u32 ticks; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB) 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ticks = ssb_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms); 3308c2ecf20Sopenharmony_ci return ticks / cc->ticks_per_ms; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int ssb_chipco_watchdog_ticks_per_ms(struct ssb_chipcommon *cc) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct ssb_bus *bus = cc->dev->bus; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { 3388c2ecf20Sopenharmony_ci /* based on 32KHz ILP clock */ 3398c2ecf20Sopenharmony_ci return 32; 3408c2ecf20Sopenharmony_ci } else { 3418c2ecf20Sopenharmony_ci if (cc->dev->id.revision < 18) 3428c2ecf20Sopenharmony_ci return ssb_clockspeed(bus) / 1000; 3438c2ecf20Sopenharmony_ci else 3448c2ecf20Sopenharmony_ci return ssb_chipco_alp_clock(cc) / 1000; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_civoid ssb_chipcommon_init(struct ssb_chipcommon *cc) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci if (!cc->dev) 3518c2ecf20Sopenharmony_ci return; /* We don't have a ChipCommon */ 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci spin_lock_init(&cc->gpio_lock); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (cc->dev->id.revision >= 11) 3568c2ecf20Sopenharmony_ci cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); 3578c2ecf20Sopenharmony_ci dev_dbg(cc->dev->dev, "chipcommon status is 0x%x\n", cc->status); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (cc->dev->id.revision >= 20) { 3608c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0); 3618c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0); 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ssb_pmu_init(cc); 3658c2ecf20Sopenharmony_ci chipco_powercontrol_init(cc); 3668c2ecf20Sopenharmony_ci ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); 3678c2ecf20Sopenharmony_ci calc_fast_powerup_delay(cc); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (cc->dev->bus->bustype == SSB_BUSTYPE_SSB) { 3708c2ecf20Sopenharmony_ci cc->ticks_per_ms = ssb_chipco_watchdog_ticks_per_ms(cc); 3718c2ecf20Sopenharmony_ci cc->max_timer_ms = ssb_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_civoid ssb_chipco_suspend(struct ssb_chipcommon *cc) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci if (!cc->dev) 3788c2ecf20Sopenharmony_ci return; 3798c2ecf20Sopenharmony_ci ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_civoid ssb_chipco_resume(struct ssb_chipcommon *cc) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci if (!cc->dev) 3858c2ecf20Sopenharmony_ci return; 3868c2ecf20Sopenharmony_ci chipco_powercontrol_init(cc); 3878c2ecf20Sopenharmony_ci ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci/* Get the processor clock */ 3918c2ecf20Sopenharmony_civoid ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, 3928c2ecf20Sopenharmony_ci u32 *plltype, u32 *n, u32 *m) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); 3958c2ecf20Sopenharmony_ci *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); 3968c2ecf20Sopenharmony_ci switch (*plltype) { 3978c2ecf20Sopenharmony_ci case SSB_PLLTYPE_2: 3988c2ecf20Sopenharmony_ci case SSB_PLLTYPE_4: 3998c2ecf20Sopenharmony_ci case SSB_PLLTYPE_6: 4008c2ecf20Sopenharmony_ci case SSB_PLLTYPE_7: 4018c2ecf20Sopenharmony_ci *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci case SSB_PLLTYPE_3: 4048c2ecf20Sopenharmony_ci /* 5350 uses m2 to control mips */ 4058c2ecf20Sopenharmony_ci *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci default: 4088c2ecf20Sopenharmony_ci *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/* Get the bus clock */ 4148c2ecf20Sopenharmony_civoid ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, 4158c2ecf20Sopenharmony_ci u32 *plltype, u32 *n, u32 *m) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); 4188c2ecf20Sopenharmony_ci *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); 4198c2ecf20Sopenharmony_ci switch (*plltype) { 4208c2ecf20Sopenharmony_ci case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */ 4218c2ecf20Sopenharmony_ci *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */ 4248c2ecf20Sopenharmony_ci if (cc->dev->bus->chip_id != 0x5365) { 4258c2ecf20Sopenharmony_ci *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci fallthrough; 4298c2ecf20Sopenharmony_ci default: 4308c2ecf20Sopenharmony_ci *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_civoid ssb_chipco_timing_init(struct ssb_chipcommon *cc, 4358c2ecf20Sopenharmony_ci unsigned long ns) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct ssb_device *dev = cc->dev; 4388c2ecf20Sopenharmony_ci struct ssb_bus *bus = dev->bus; 4398c2ecf20Sopenharmony_ci u32 tmp; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* set register for external IO to control LED. */ 4428c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11); 4438c2ecf20Sopenharmony_ci tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ 4448c2ecf20Sopenharmony_ci tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */ 4458c2ecf20Sopenharmony_ci tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */ 4468c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Set timing for the flash */ 4498c2ecf20Sopenharmony_ci tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */ 4508c2ecf20Sopenharmony_ci tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */ 4518c2ecf20Sopenharmony_ci tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */ 4528c2ecf20Sopenharmony_ci if ((bus->chip_id == 0x5365) || 4538c2ecf20Sopenharmony_ci (dev->id.revision < 9)) 4548c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp); 4558c2ecf20Sopenharmony_ci if ((bus->chip_id == 0x5365) || 4568c2ecf20Sopenharmony_ci (dev->id.revision < 9) || 4578c2ecf20Sopenharmony_ci ((bus->chip_id == 0x5350) && (bus->chip_rev == 0))) 4588c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (bus->chip_id == 0x5350) { 4618c2ecf20Sopenharmony_ci /* Enable EXTIF */ 4628c2ecf20Sopenharmony_ci tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */ 4638c2ecf20Sopenharmony_ci tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */ 4648c2ecf20Sopenharmony_ci tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */ 4658c2ecf20Sopenharmony_ci tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */ 4668c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */ 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ 4718c2ecf20Sopenharmony_ciu32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci u32 maxt; 4748c2ecf20Sopenharmony_ci enum ssb_clkmode clkmode; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci maxt = ssb_chipco_watchdog_get_max_timer(cc); 4778c2ecf20Sopenharmony_ci if (cc->capabilities & SSB_CHIPCO_CAP_PMU) { 4788c2ecf20Sopenharmony_ci if (ticks == 1) 4798c2ecf20Sopenharmony_ci ticks = 2; 4808c2ecf20Sopenharmony_ci else if (ticks > maxt) 4818c2ecf20Sopenharmony_ci ticks = maxt; 4828c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_PMU_WATCHDOG, ticks); 4838c2ecf20Sopenharmony_ci } else { 4848c2ecf20Sopenharmony_ci clkmode = ticks ? SSB_CLKMODE_FAST : SSB_CLKMODE_DYNAMIC; 4858c2ecf20Sopenharmony_ci ssb_chipco_set_clockmode(cc, clkmode); 4868c2ecf20Sopenharmony_ci if (ticks > maxt) 4878c2ecf20Sopenharmony_ci ticks = maxt; 4888c2ecf20Sopenharmony_ci /* instant NMI */ 4898c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci return ticks; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_civoid ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci chipco_write32_masked(cc, SSB_CHIPCO_IRQMASK, mask, value); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ciu32 ssb_chipco_irq_status(struct ssb_chipcommon *cc, u32 mask) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci return chipco_read32(cc, SSB_CHIPCO_IRQSTAT) & mask; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ciu32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ciu32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci unsigned long flags; 5128c2ecf20Sopenharmony_ci u32 res = 0; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 5158c2ecf20Sopenharmony_ci res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); 5168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return res; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ciu32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci unsigned long flags; 5248c2ecf20Sopenharmony_ci u32 res = 0; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 5278c2ecf20Sopenharmony_ci res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); 5288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return res; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ciu32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci unsigned long flags; 5368c2ecf20Sopenharmony_ci u32 res = 0; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 5398c2ecf20Sopenharmony_ci res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); 5408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return res; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ssb_chipco_gpio_control); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ciu32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci unsigned long flags; 5498c2ecf20Sopenharmony_ci u32 res = 0; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 5528c2ecf20Sopenharmony_ci res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); 5538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return res; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ciu32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci unsigned long flags; 5618c2ecf20Sopenharmony_ci u32 res = 0; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 5648c2ecf20Sopenharmony_ci res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); 5658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return res; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ciu32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci unsigned long flags; 5738c2ecf20Sopenharmony_ci u32 res = 0; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (cc->dev->id.revision < 20) 5768c2ecf20Sopenharmony_ci return 0xffffffff; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 5798c2ecf20Sopenharmony_ci res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); 5808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci return res; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ciu32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci unsigned long flags; 5888c2ecf20Sopenharmony_ci u32 res = 0; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (cc->dev->id.revision < 20) 5918c2ecf20Sopenharmony_ci return 0xffffffff; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci spin_lock_irqsave(&cc->gpio_lock, flags); 5948c2ecf20Sopenharmony_ci res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); 5958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cc->gpio_lock, flags); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return res; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci#ifdef CONFIG_SSB_SERIAL 6018c2ecf20Sopenharmony_ciint ssb_chipco_serial_init(struct ssb_chipcommon *cc, 6028c2ecf20Sopenharmony_ci struct ssb_serial_port *ports) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct ssb_bus *bus = cc->dev->bus; 6058c2ecf20Sopenharmony_ci int nr_ports = 0; 6068c2ecf20Sopenharmony_ci u32 plltype; 6078c2ecf20Sopenharmony_ci unsigned int irq; 6088c2ecf20Sopenharmony_ci u32 baud_base, div; 6098c2ecf20Sopenharmony_ci u32 i, n; 6108c2ecf20Sopenharmony_ci unsigned int ccrev = cc->dev->id.revision; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); 6138c2ecf20Sopenharmony_ci irq = ssb_mips_irq(cc->dev); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (plltype == SSB_PLLTYPE_1) { 6168c2ecf20Sopenharmony_ci /* PLL clock */ 6178c2ecf20Sopenharmony_ci baud_base = ssb_calc_clock_rate(plltype, 6188c2ecf20Sopenharmony_ci chipco_read32(cc, SSB_CHIPCO_CLOCK_N), 6198c2ecf20Sopenharmony_ci chipco_read32(cc, SSB_CHIPCO_CLOCK_M2)); 6208c2ecf20Sopenharmony_ci div = 1; 6218c2ecf20Sopenharmony_ci } else { 6228c2ecf20Sopenharmony_ci if (ccrev == 20) { 6238c2ecf20Sopenharmony_ci /* BCM5354 uses constant 25MHz clock */ 6248c2ecf20Sopenharmony_ci baud_base = 25000000; 6258c2ecf20Sopenharmony_ci div = 48; 6268c2ecf20Sopenharmony_ci /* Set the override bit so we don't divide it */ 6278c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_CORECTL, 6288c2ecf20Sopenharmony_ci chipco_read32(cc, SSB_CHIPCO_CORECTL) 6298c2ecf20Sopenharmony_ci | SSB_CHIPCO_CORECTL_UARTCLK0); 6308c2ecf20Sopenharmony_ci } else if ((ccrev >= 11) && (ccrev != 15)) { 6318c2ecf20Sopenharmony_ci baud_base = ssb_chipco_alp_clock(cc); 6328c2ecf20Sopenharmony_ci div = 1; 6338c2ecf20Sopenharmony_ci if (ccrev >= 21) { 6348c2ecf20Sopenharmony_ci /* Turn off UART clock before switching clocksource. */ 6358c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_CORECTL, 6368c2ecf20Sopenharmony_ci chipco_read32(cc, SSB_CHIPCO_CORECTL) 6378c2ecf20Sopenharmony_ci & ~SSB_CHIPCO_CORECTL_UARTCLKEN); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci /* Set the override bit so we don't divide it */ 6408c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_CORECTL, 6418c2ecf20Sopenharmony_ci chipco_read32(cc, SSB_CHIPCO_CORECTL) 6428c2ecf20Sopenharmony_ci | SSB_CHIPCO_CORECTL_UARTCLK0); 6438c2ecf20Sopenharmony_ci if (ccrev >= 21) { 6448c2ecf20Sopenharmony_ci /* Re-enable the UART clock. */ 6458c2ecf20Sopenharmony_ci chipco_write32(cc, SSB_CHIPCO_CORECTL, 6468c2ecf20Sopenharmony_ci chipco_read32(cc, SSB_CHIPCO_CORECTL) 6478c2ecf20Sopenharmony_ci | SSB_CHIPCO_CORECTL_UARTCLKEN); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci } else if (ccrev >= 3) { 6508c2ecf20Sopenharmony_ci /* Internal backplane clock */ 6518c2ecf20Sopenharmony_ci baud_base = ssb_clockspeed(bus); 6528c2ecf20Sopenharmony_ci div = chipco_read32(cc, SSB_CHIPCO_CLKDIV) 6538c2ecf20Sopenharmony_ci & SSB_CHIPCO_CLKDIV_UART; 6548c2ecf20Sopenharmony_ci } else { 6558c2ecf20Sopenharmony_ci /* Fixed internal backplane clock */ 6568c2ecf20Sopenharmony_ci baud_base = 88000000; 6578c2ecf20Sopenharmony_ci div = 48; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Clock source depends on strapping if UartClkOverride is unset */ 6618c2ecf20Sopenharmony_ci if ((ccrev > 0) && 6628c2ecf20Sopenharmony_ci !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) { 6638c2ecf20Sopenharmony_ci if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) == 6648c2ecf20Sopenharmony_ci SSB_CHIPCO_CAP_UARTCLK_INT) { 6658c2ecf20Sopenharmony_ci /* Internal divided backplane clock */ 6668c2ecf20Sopenharmony_ci baud_base /= div; 6678c2ecf20Sopenharmony_ci } else { 6688c2ecf20Sopenharmony_ci /* Assume external clock of 1.8432 MHz */ 6698c2ecf20Sopenharmony_ci baud_base = 1843200; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* Determine the registers of the UARTs */ 6758c2ecf20Sopenharmony_ci n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART); 6768c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 6778c2ecf20Sopenharmony_ci void __iomem *cc_mmio; 6788c2ecf20Sopenharmony_ci void __iomem *uart_regs; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE); 6818c2ecf20Sopenharmony_ci uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA; 6828c2ecf20Sopenharmony_ci /* Offset changed at after rev 0 */ 6838c2ecf20Sopenharmony_ci if (ccrev == 0) 6848c2ecf20Sopenharmony_ci uart_regs += (i * 8); 6858c2ecf20Sopenharmony_ci else 6868c2ecf20Sopenharmony_ci uart_regs += (i * 256); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci nr_ports++; 6898c2ecf20Sopenharmony_ci ports[i].regs = uart_regs; 6908c2ecf20Sopenharmony_ci ports[i].irq = irq; 6918c2ecf20Sopenharmony_ci ports[i].baud_base = baud_base; 6928c2ecf20Sopenharmony_ci ports[i].reg_shift = 0; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return nr_ports; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci#endif /* CONFIG_SSB_SERIAL */ 698