| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 1 | /* | 
 | 2 |  * Sonics Silicon Backplane | 
 | 3 |  * Broadcom EXTIF core driver | 
 | 4 |  * | 
 | 5 |  * Copyright 2005, Broadcom Corporation | 
 | 6 |  * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> | 
 | 7 |  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org> | 
 | 8 |  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net> | 
 | 9 |  * | 
 | 10 |  * Licensed under the GNU/GPL. See COPYING for details. | 
 | 11 |  */ | 
 | 12 |  | 
 | 13 | #include <linux/serial.h> | 
 | 14 | #include <linux/serial_core.h> | 
 | 15 | #include <linux/serial_reg.h> | 
 | 16 |  | 
 | 17 | #include "ssb_private.h" | 
 | 18 |  | 
 | 19 |  | 
 | 20 | static inline u32 extif_read32(struct ssb_extif *extif, u16 offset) | 
 | 21 | { | 
 | 22 | 	return ssb_read32(extif->dev, offset); | 
 | 23 | } | 
 | 24 |  | 
 | 25 | static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value) | 
 | 26 | { | 
 | 27 | 	ssb_write32(extif->dev, offset, value); | 
 | 28 | } | 
 | 29 |  | 
| Michael Buesch | c2bcbe6 | 2008-02-19 14:53:35 +0100 | [diff] [blame] | 30 | static inline u32 extif_write32_masked(struct ssb_extif *extif, u16 offset, | 
 | 31 | 				       u32 mask, u32 value) | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 32 | { | 
 | 33 | 	value &= mask; | 
 | 34 | 	value |= extif_read32(extif, offset) & ~mask; | 
 | 35 | 	extif_write32(extif, offset, value); | 
| Michael Buesch | c2bcbe6 | 2008-02-19 14:53:35 +0100 | [diff] [blame] | 36 |  | 
 | 37 | 	return value; | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 38 | } | 
 | 39 |  | 
 | 40 | #ifdef CONFIG_SSB_SERIAL | 
 | 41 | static bool serial_exists(u8 *regs) | 
 | 42 | { | 
 | 43 | 	u8 save_mcr, msr = 0; | 
 | 44 |  | 
 | 45 | 	if (regs) { | 
 | 46 | 		save_mcr = regs[UART_MCR]; | 
 | 47 | 		regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS); | 
 | 48 | 		msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI | 
 | 49 | 					| UART_MSR_CTS | UART_MSR_DSR); | 
 | 50 | 		regs[UART_MCR] = save_mcr; | 
 | 51 | 	} | 
 | 52 | 	return (msr == (UART_MSR_DCD | UART_MSR_CTS)); | 
 | 53 | } | 
 | 54 |  | 
 | 55 | int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports) | 
 | 56 | { | 
 | 57 | 	u32 i, nr_ports = 0; | 
 | 58 |  | 
 | 59 | 	/* Disable GPIO interrupt initially */ | 
 | 60 | 	extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0); | 
 | 61 | 	extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0); | 
 | 62 |  | 
 | 63 | 	for (i = 0; i < 2; i++) { | 
 | 64 | 		void __iomem *uart_regs; | 
 | 65 |  | 
 | 66 | 		uart_regs = ioremap_nocache(SSB_EUART, 16); | 
 | 67 | 		if (uart_regs) { | 
 | 68 | 			uart_regs += (i * 8); | 
 | 69 |  | 
 | 70 | 			if (serial_exists(uart_regs) && ports) { | 
 | 71 | 				extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2); | 
 | 72 |  | 
 | 73 | 				nr_ports++; | 
 | 74 | 				ports[i].regs = uart_regs; | 
 | 75 | 				ports[i].irq = 2; | 
 | 76 | 				ports[i].baud_base = 13500000; | 
 | 77 | 				ports[i].reg_shift = 0; | 
 | 78 | 			} | 
 | 79 | 			iounmap(uart_regs); | 
 | 80 | 		} | 
 | 81 | 	} | 
 | 82 | 	return nr_ports; | 
 | 83 | } | 
 | 84 | #endif /* CONFIG_SSB_SERIAL */ | 
 | 85 |  | 
 | 86 | void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns) | 
 | 87 | { | 
 | 88 | 	u32 tmp; | 
 | 89 |  | 
 | 90 | 	/* Initialize extif so we can get to the LEDs and external UART */ | 
 | 91 | 	extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN); | 
 | 92 |  | 
 | 93 | 	/* Set timing for the flash */ | 
 | 94 | 	tmp  = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; | 
 | 95 | 	tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; | 
 | 96 | 	tmp |= DIV_ROUND_UP(120, ns); | 
 | 97 | 	extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); | 
 | 98 |  | 
 | 99 | 	/* Set programmable interface timing for external uart */ | 
 | 100 | 	tmp  = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; | 
 | 101 | 	tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; | 
 | 102 | 	tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; | 
 | 103 | 	tmp |= DIV_ROUND_UP(120, ns); | 
 | 104 | 	extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); | 
 | 105 | } | 
 | 106 |  | 
 | 107 | void ssb_extif_get_clockcontrol(struct ssb_extif *extif, | 
 | 108 | 				u32 *pll_type, u32 *n, u32 *m) | 
 | 109 | { | 
 | 110 | 	*pll_type = SSB_PLLTYPE_1; | 
 | 111 | 	*n = extif_read32(extif, SSB_EXTIF_CLOCK_N); | 
 | 112 | 	*m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); | 
 | 113 | } | 
 | 114 |  | 
| Michael Buesch | 42bfad4 | 2008-02-19 12:41:30 +0100 | [diff] [blame] | 115 | void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, | 
 | 116 | 				  u32 ticks) | 
 | 117 | { | 
 | 118 | 	extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); | 
 | 119 | } | 
 | 120 |  | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 121 | u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) | 
 | 122 | { | 
 | 123 | 	return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; | 
 | 124 | } | 
 | 125 |  | 
| Michael Buesch | c2bcbe6 | 2008-02-19 14:53:35 +0100 | [diff] [blame] | 126 | u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 127 | { | 
 | 128 | 	return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), | 
 | 129 | 				   mask, value); | 
 | 130 | } | 
 | 131 |  | 
| Michael Buesch | c2bcbe6 | 2008-02-19 14:53:35 +0100 | [diff] [blame] | 132 | u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 133 | { | 
 | 134 | 	return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), | 
 | 135 | 				   mask, value); | 
 | 136 | } | 
 | 137 |  | 
| Michael Buesch | c2bcbe6 | 2008-02-19 14:53:35 +0100 | [diff] [blame] | 138 | u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) | 
 | 139 | { | 
 | 140 | 	return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); | 
 | 141 | } | 
| Michael Buesch | c2bcbe6 | 2008-02-19 14:53:35 +0100 | [diff] [blame] | 142 |  | 
 | 143 | u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) | 
 | 144 | { | 
 | 145 | 	return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); | 
 | 146 | } |