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