1276685Sadrian/*-
2276685Sadrian * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>
3276685Sadrian * All rights reserved.
4276685Sadrian *
5276685Sadrian * Redistribution and use in source and binary forms, with or without
6276685Sadrian * modification, are permitted provided that the following conditions
7276685Sadrian * are met:
8276685Sadrian * 1. Redistributions of source code must retain the above copyright
9276685Sadrian *    notice, this list of conditions and the following disclaimer.
10276685Sadrian * 2. Redistributions in binary form must reproduce the above copyright
11276685Sadrian *    notice, this list of conditions and the following disclaimer in the
12276685Sadrian *    documentation and/or other materials provided with the distribution.
13276685Sadrian *
14276685Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15276685Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16276685Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17276685Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18276685Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19276685Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20276685Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21276685Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22276685Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23276685Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24276685Sadrian * SUCH DAMAGE.
25276685Sadrian */
26276685Sadrian
27276685Sadrian#include <sys/cdefs.h>
28276685Sadrian__FBSDID("$FreeBSD$");
29276685Sadrian
30276685Sadrian#include "opt_ddb.h"
31276685Sadrian
32276685Sadrian#include <sys/param.h>
33276685Sadrian#include <sys/conf.h>
34276685Sadrian#include <sys/kernel.h>
35276685Sadrian#include <sys/systm.h>
36276685Sadrian#include <sys/bus.h>
37276685Sadrian#include <sys/cons.h>
38276685Sadrian#include <sys/kdb.h>
39276685Sadrian#include <sys/reboot.h>
40276685Sadrian
41276685Sadrian#include <vm/vm.h>
42276685Sadrian#include <vm/vm_page.h>
43276685Sadrian
44276685Sadrian#include <net/ethernet.h>
45276685Sadrian
46276685Sadrian#include <machine/clock.h>
47276685Sadrian#include <machine/cpu.h>
48276685Sadrian#include <machine/cpuregs.h>
49276685Sadrian#include <machine/hwfunc.h>
50276685Sadrian#include <machine/md_var.h>
51276685Sadrian#include <machine/trap.h>
52276685Sadrian#include <machine/vmparam.h>
53276685Sadrian
54276685Sadrian#include <mips/atheros/ar71xxreg.h>
55276685Sadrian//#include <mips/atheros/ar934xreg.h>
56276685Sadrian#include <mips/atheros/qca955xreg.h>
57276685Sadrian
58276685Sadrian#include <mips/atheros/ar71xx_cpudef.h>
59276685Sadrian#include <mips/atheros/ar71xx_setup.h>
60276685Sadrian
61276685Sadrian#include <mips/atheros/ar71xx_chip.h>
62276685Sadrian
63276685Sadrian#include <mips/atheros/qca955x_chip.h>
64276685Sadrian
65276685Sadrianstatic void
66276685Sadrianqca955x_chip_detect_mem_size(void)
67276685Sadrian{
68276685Sadrian}
69276685Sadrian
70276685Sadrianstatic void
71276685Sadrianqca955x_chip_detect_sys_frequency(void)
72276685Sadrian{
73276685Sadrian	unsigned long ref_rate;
74276685Sadrian	unsigned long cpu_rate;
75276685Sadrian	unsigned long ddr_rate;
76276685Sadrian	unsigned long ahb_rate;
77276685Sadrian	uint32_t pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv;
78276685Sadrian	uint32_t cpu_pll, ddr_pll;
79276685Sadrian	uint32_t bootstrap;
80276685Sadrian
81276685Sadrian	bootstrap = ATH_READ_REG(QCA955X_RESET_REG_BOOTSTRAP);
82276685Sadrian	if (bootstrap &	QCA955X_BOOTSTRAP_REF_CLK_40)
83276685Sadrian		ref_rate = 40 * 1000 * 1000;
84276685Sadrian	else
85276685Sadrian		ref_rate = 25 * 1000 * 1000;
86276685Sadrian
87276685Sadrian	pll = ATH_READ_REG(QCA955X_PLL_CPU_CONFIG_REG);
88276685Sadrian	out_div = (pll >> QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
89276685Sadrian		  QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK;
90276685Sadrian	ref_div = (pll >> QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
91276685Sadrian		  QCA955X_PLL_CPU_CONFIG_REFDIV_MASK;
92276685Sadrian	nint = (pll >> QCA955X_PLL_CPU_CONFIG_NINT_SHIFT) &
93276685Sadrian	       QCA955X_PLL_CPU_CONFIG_NINT_MASK;
94276685Sadrian	frac = (pll >> QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
95276685Sadrian	       QCA955X_PLL_CPU_CONFIG_NFRAC_MASK;
96276685Sadrian
97276685Sadrian	cpu_pll = nint * ref_rate / ref_div;
98276685Sadrian	cpu_pll += frac * ref_rate / (ref_div * (1 << 6));
99276685Sadrian	cpu_pll /= (1 << out_div);
100276685Sadrian
101276685Sadrian	pll = ATH_READ_REG(QCA955X_PLL_DDR_CONFIG_REG);
102276685Sadrian	out_div = (pll >> QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
103276685Sadrian		  QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK;
104276685Sadrian	ref_div = (pll >> QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
105276685Sadrian		  QCA955X_PLL_DDR_CONFIG_REFDIV_MASK;
106276685Sadrian	nint = (pll >> QCA955X_PLL_DDR_CONFIG_NINT_SHIFT) &
107276685Sadrian	       QCA955X_PLL_DDR_CONFIG_NINT_MASK;
108276685Sadrian	frac = (pll >> QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
109276685Sadrian	       QCA955X_PLL_DDR_CONFIG_NFRAC_MASK;
110276685Sadrian
111276685Sadrian	ddr_pll = nint * ref_rate / ref_div;
112276685Sadrian	ddr_pll += frac * ref_rate / (ref_div * (1 << 10));
113276685Sadrian	ddr_pll /= (1 << out_div);
114276685Sadrian
115276685Sadrian	clk_ctrl = ATH_READ_REG(QCA955X_PLL_CLK_CTRL_REG);
116276685Sadrian
117276685Sadrian	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
118276685Sadrian		  QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
119276685Sadrian
120276685Sadrian	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
121276685Sadrian		cpu_rate = ref_rate;
122276685Sadrian	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
123276685Sadrian		cpu_rate = ddr_pll / (postdiv + 1);
124276685Sadrian	else
125276685Sadrian		cpu_rate = cpu_pll / (postdiv + 1);
126276685Sadrian
127276685Sadrian	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
128276685Sadrian		  QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
129276685Sadrian
130276685Sadrian	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
131276685Sadrian		ddr_rate = ref_rate;
132276685Sadrian	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
133276685Sadrian		ddr_rate = cpu_pll / (postdiv + 1);
134276685Sadrian	else
135276685Sadrian		ddr_rate = ddr_pll / (postdiv + 1);
136276685Sadrian
137276685Sadrian	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
138276685Sadrian		  QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
139276685Sadrian
140276685Sadrian	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
141276685Sadrian		ahb_rate = ref_rate;
142276685Sadrian	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
143276685Sadrian		ahb_rate = ddr_pll / (postdiv + 1);
144276685Sadrian	else
145276685Sadrian		ahb_rate = cpu_pll / (postdiv + 1);
146276685Sadrian
147276685Sadrian	u_ar71xx_ddr_freq = ddr_rate;
148276685Sadrian	u_ar71xx_cpu_freq = cpu_rate;
149276685Sadrian	u_ar71xx_ahb_freq = ahb_rate;
150276685Sadrian
151276685Sadrian	u_ar71xx_wdt_freq = ref_rate;
152276685Sadrian	u_ar71xx_uart_freq = ref_rate;
153276685Sadrian	u_ar71xx_mdio_freq = ref_rate;
154276690Sadrian	u_ar71xx_refclk = ref_rate;
155276685Sadrian}
156276685Sadrian
157276685Sadrianstatic void
158276685Sadrianqca955x_chip_device_stop(uint32_t mask)
159276685Sadrian{
160276685Sadrian	uint32_t reg;
161276685Sadrian
162276685Sadrian	reg = ATH_READ_REG(QCA955X_RESET_REG_RESET_MODULE);
163276685Sadrian	ATH_WRITE_REG(QCA955X_RESET_REG_RESET_MODULE, reg | mask);
164276685Sadrian}
165276685Sadrian
166276685Sadrianstatic void
167276685Sadrianqca955x_chip_device_start(uint32_t mask)
168276685Sadrian{
169276685Sadrian	uint32_t reg;
170276685Sadrian
171276685Sadrian	reg = ATH_READ_REG(QCA955X_RESET_REG_RESET_MODULE);
172276685Sadrian	ATH_WRITE_REG(QCA955X_RESET_REG_RESET_MODULE, reg & ~mask);
173276685Sadrian}
174276685Sadrian
175276685Sadrianstatic int
176276685Sadrianqca955x_chip_device_stopped(uint32_t mask)
177276685Sadrian{
178276685Sadrian	uint32_t reg;
179276685Sadrian
180276685Sadrian	reg = ATH_READ_REG(QCA955X_RESET_REG_RESET_MODULE);
181276685Sadrian	return ((reg & mask) == mask);
182276685Sadrian}
183276685Sadrian
184276685Sadrianstatic void
185276685Sadrianqca955x_chip_set_mii_speed(uint32_t unit, uint32_t speed)
186276685Sadrian{
187276685Sadrian
188276685Sadrian	/* XXX TODO */
189276685Sadrian	return;
190276685Sadrian}
191276685Sadrian
192276685Sadrianstatic void
193276685Sadrianqca955x_chip_set_pll_ge(int unit, int speed, uint32_t pll)
194276685Sadrian{
195276685Sadrian	switch (unit) {
196276685Sadrian	case 0:
197279479Sadrian		ATH_WRITE_REG(QCA955X_PLL_ETH_XMII_CONTROL_REG, pll);
198276685Sadrian		break;
199276685Sadrian	case 1:
200279479Sadrian		ATH_WRITE_REG(QCA955X_PLL_ETH_SGMII_CONTROL_REG, pll);
201276685Sadrian		break;
202276685Sadrian	default:
203276685Sadrian		printf("%s: invalid PLL set for arge unit: %d\n",
204276685Sadrian		    __func__, unit);
205276685Sadrian		return;
206276685Sadrian	}
207276685Sadrian}
208276685Sadrian
209276685Sadrianstatic void
210285121Sadrianqca955x_chip_ddr_flush(ar71xx_flush_ddr_id_t id)
211276685Sadrian{
212279579Sadrian
213285121Sadrian	switch (id) {
214285121Sadrian	case AR71XX_CPU_DDR_FLUSH_GE0:
215279579Sadrian		ar71xx_ddr_flush(QCA955X_DDR_REG_FLUSH_GE0);
216276685Sadrian		break;
217285121Sadrian	case AR71XX_CPU_DDR_FLUSH_GE1:
218279579Sadrian		ar71xx_ddr_flush(QCA955X_DDR_REG_FLUSH_GE1);
219276685Sadrian		break;
220285121Sadrian	case AR71XX_CPU_DDR_FLUSH_USB:
221285121Sadrian		ar71xx_ddr_flush(QCA955X_DDR_REG_FLUSH_USB);
222285121Sadrian		break;
223285121Sadrian	case AR71XX_CPU_DDR_FLUSH_PCIE:
224285121Sadrian		ar71xx_ddr_flush(QCA955X_DDR_REG_FLUSH_PCIE);
225285121Sadrian		break;
226285121Sadrian	case AR71XX_CPU_DDR_FLUSH_WMAC:
227285121Sadrian		ar71xx_ddr_flush(QCA955X_DDR_REG_FLUSH_WMAC);
228285121Sadrian		break;
229285121Sadrian	case AR71XX_CPU_DDR_FLUSH_PCIE_EP:
230285121Sadrian		ar71xx_ddr_flush(QCA955X_DDR_REG_FLUSH_SRC1);
231285121Sadrian		break;
232285121Sadrian	case AR71XX_CPU_DDR_FLUSH_CHECKSUM:
233285121Sadrian		ar71xx_ddr_flush(QCA955X_DDR_REG_FLUSH_SRC2);
234285121Sadrian		break;
235276685Sadrian	default:
236285121Sadrian		printf("%s: invalid flush (%d)\n", __func__, id);
237276685Sadrian	}
238276685Sadrian}
239276685Sadrian
240276685Sadrianstatic uint32_t
241276685Sadrianqca955x_chip_get_eth_pll(unsigned int mac, int speed)
242276685Sadrian{
243276685Sadrian	uint32_t pll;
244276685Sadrian
245276685Sadrian	switch (speed) {
246276685Sadrian	case 10:
247279479Sadrian		pll = QCA955X_PLL_VAL_10;
248276685Sadrian		break;
249276685Sadrian	case 100:
250279479Sadrian		pll = QCA955X_PLL_VAL_100;
251276685Sadrian		break;
252276685Sadrian	case 1000:
253279479Sadrian		pll = QCA955X_PLL_VAL_1000;
254276685Sadrian		break;
255276685Sadrian	default:
256276685Sadrian		printf("%s%d: invalid speed %d\n", __func__, mac, speed);
257276685Sadrian		pll = 0;
258276685Sadrian	}
259276685Sadrian	return (pll);
260276685Sadrian}
261276685Sadrian
262276685Sadrianstatic void
263276685Sadrianqca955x_chip_reset_ethernet_switch(void)
264276685Sadrian{
265276685Sadrian#if 0
266276685Sadrian	ar71xx_device_stop(AR934X_RESET_ETH_SWITCH);
267276685Sadrian	DELAY(100);
268276685Sadrian	ar71xx_device_start(AR934X_RESET_ETH_SWITCH);
269276685Sadrian	DELAY(100);
270276685Sadrian#endif
271276685Sadrian}
272276685Sadrian
273276685Sadrianstatic void
274276685Sadrianqca955x_configure_gmac(uint32_t gmac_cfg)
275276685Sadrian{
276276685Sadrian	uint32_t reg;
277276685Sadrian
278279479Sadrian	reg = ATH_READ_REG(QCA955X_GMAC_REG_ETH_CFG);
279276685Sadrian	printf("%s: ETH_CFG=0x%08x\n", __func__, reg);
280279479Sadrian	reg &= ~(QCA955X_ETH_CFG_RGMII_EN | QCA955X_ETH_CFG_GE0_SGMII);
281276685Sadrian	reg |= gmac_cfg;
282279479Sadrian	ATH_WRITE_REG(QCA955X_GMAC_REG_ETH_CFG, reg);
283276685Sadrian}
284276685Sadrian
285276685Sadrianstatic void
286276685Sadrianqca955x_chip_init_usb_peripheral(void)
287276685Sadrian{
288276685Sadrian}
289276685Sadrian
290276685Sadrianstatic void
291276685Sadrianqca955x_chip_set_mii_if(uint32_t unit, uint32_t mii_mode)
292276685Sadrian{
293276685Sadrian
294276685Sadrian	/*
295276685Sadrian	 * XXX !
296276685Sadrian	 *
297276685Sadrian	 * Nothing to see here; although gmac0 can have its
298276685Sadrian	 * MII configuration changed, the register values
299276685Sadrian	 * are slightly different.
300276685Sadrian	 */
301276685Sadrian}
302276685Sadrian
303276685Sadrian/*
304276685Sadrian * XXX TODO: fetch default MII divider configuration
305276685Sadrian */
306276685Sadrian
307276685Sadrianstatic void
308276685Sadrianqca955x_chip_reset_wmac(void)
309276685Sadrian{
310276685Sadrian
311276685Sadrian	/* XXX TODO */
312276685Sadrian}
313276685Sadrian
314276685Sadrianstatic void
315276685Sadrianqca955x_chip_init_gmac(void)
316276685Sadrian{
317276685Sadrian	long gmac_cfg;
318276685Sadrian
319279479Sadrian	if (resource_long_value("qca955x_gmac", 0, "gmac_cfg",
320276685Sadrian	    &gmac_cfg) == 0) {
321276685Sadrian		printf("%s: gmac_cfg=0x%08lx\n",
322276685Sadrian		    __func__,
323276685Sadrian		    (long) gmac_cfg);
324279479Sadrian		qca955x_configure_gmac((uint32_t) gmac_cfg);
325276685Sadrian	}
326276685Sadrian}
327276685Sadrian
328276685Sadrian/*
329276685Sadrian * Reset the NAND Flash Controller.
330276685Sadrian *
331276685Sadrian * + active=1 means "make it active".
332276685Sadrian * + active=0 means "make it inactive".
333276685Sadrian */
334276685Sadrianstatic void
335276685Sadrianqca955x_chip_reset_nfc(int active)
336276685Sadrian{
337276685Sadrian#if 0
338276685Sadrian	if (active) {
339276685Sadrian		ar71xx_device_start(AR934X_RESET_NANDF);
340276685Sadrian		DELAY(100);
341276685Sadrian
342276685Sadrian		ar71xx_device_start(AR934X_RESET_ETH_SWITCH_ANALOG);
343276685Sadrian		DELAY(250);
344276685Sadrian	} else {
345276685Sadrian		ar71xx_device_stop(AR934X_RESET_ETH_SWITCH_ANALOG);
346276685Sadrian		DELAY(250);
347276685Sadrian
348276685Sadrian		ar71xx_device_stop(AR934X_RESET_NANDF);
349276685Sadrian		DELAY(100);
350276685Sadrian	}
351276685Sadrian#endif
352276685Sadrian}
353276685Sadrian
354276685Sadrian/*
355276685Sadrian * Configure the GPIO output mux setup.
356276685Sadrian *
357285073Sadrian * The QCA955x has an output mux which allowed
358276685Sadrian * certain functions to be configured on any pin.
359276685Sadrian * Specifically, the switch PHY link LEDs and
360276685Sadrian * WMAC external RX LNA switches are not limited to
361276685Sadrian * a specific GPIO pin.
362276685Sadrian */
363276685Sadrianstatic void
364276685Sadrianqca955x_chip_gpio_output_configure(int gpio, uint8_t func)
365276685Sadrian{
366276685Sadrian	uint32_t reg, s;
367276685Sadrian	uint32_t t;
368276685Sadrian
369276685Sadrian	if (gpio > QCA955X_GPIO_COUNT)
370276685Sadrian		return;
371276685Sadrian
372298848Spfg	reg = QCA955X_GPIO_REG_OUT_FUNC0 + rounddown(gpio, 4);
373276685Sadrian	s = 8 * (gpio % 4);
374276685Sadrian
375276685Sadrian	/* read-modify-write */
376276685Sadrian	t = ATH_READ_REG(AR71XX_GPIO_BASE + reg);
377276685Sadrian	t &= ~(0xff << s);
378276685Sadrian	t |= func << s;
379276685Sadrian	ATH_WRITE_REG(AR71XX_GPIO_BASE + reg, t);
380276685Sadrian
381276685Sadrian	/* flush write */
382276685Sadrian	ATH_READ_REG(AR71XX_GPIO_BASE + reg);
383276685Sadrian}
384276685Sadrian
385276685Sadrianstruct ar71xx_cpu_def qca955x_chip_def = {
386276685Sadrian	&qca955x_chip_detect_mem_size,
387276685Sadrian	&qca955x_chip_detect_sys_frequency,
388276685Sadrian	&qca955x_chip_device_stop,
389276685Sadrian	&qca955x_chip_device_start,
390276685Sadrian	&qca955x_chip_device_stopped,
391276685Sadrian	&qca955x_chip_set_pll_ge,
392276685Sadrian	&qca955x_chip_set_mii_speed,
393276685Sadrian	&qca955x_chip_set_mii_if,
394276685Sadrian	&qca955x_chip_get_eth_pll,
395285121Sadrian	&qca955x_chip_ddr_flush,
396276685Sadrian	&qca955x_chip_init_usb_peripheral,
397276685Sadrian	&qca955x_chip_reset_ethernet_switch,
398276685Sadrian	&qca955x_chip_reset_wmac,
399276685Sadrian	&qca955x_chip_init_gmac,
400276685Sadrian	&qca955x_chip_reset_nfc,
401276685Sadrian	&qca955x_chip_gpio_output_configure,
402276685Sadrian};
403