1/*
2 * HND SiliconBackplane Gigabit Ethernet core software interface
3 *
4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: hndgige.c 419467 2013-08-21 09:19:48Z $
19 */
20
21#include <bcm_cfg.h>
22#include <typedefs.h>
23#include <osl.h>
24#include <pcicfg.h>
25#include <hndsoc.h>
26#include <bcmutils.h>
27#include <siutils.h>
28#include <sbgige.h>
29#include <hndpci.h>
30#include <hndgige.h>
31
32/*
33 * Setup the gige core.
34 * Resetting the core will lose all settings.
35 */
36void
37hndgige_init(si_t *sih, uint32 unit, bool *rgmii)
38{
39	volatile pci_config_regs *pci;
40	sbgige_pcishim_t *ocp;
41	sbconfig_t *sb;
42	osl_t *osh;
43	uint32 statelow;
44	uint32 statehigh;
45	uint32 base;
46	uint32 idx;
47	void *regs;
48
49	/* Sanity checks */
50	ASSERT(sih);
51	ASSERT(rgmii);
52
53	idx = si_coreidx(sih);
54
55	/* point to the gige core registers */
56	regs = si_setcore(sih, GIGETH_CORE_ID, unit);
57	ASSERT(regs);
58
59	osh = si_osh(sih);
60
61	pci = &((sbgige_t *)regs)->pcicfg;
62	ocp = &((sbgige_t *)regs)->pcishim;
63	sb = &((sbgige_t *)regs)->sbconfig;
64
65	/* Enable the core clock and memory access */
66	if (!si_iscoreup(sih))
67		si_core_reset(sih, 0, 0);
68
69	/*
70	 * Setup the 64K memory-mapped region base address through BAR0.
71	 * Leave the other BAR values alone.
72	 */
73	base = si_addrspace(sih, 1);
74	W_REG(osh, &pci->base[0], base);
75	W_REG(osh, &pci->base[1], 0);
76
77	/*
78	 * Enable the PCI memory access anyway. Any PCI config commands
79	 * issued before the core is enabled will go to the emulation
80	 * only and will not go to the real PCI config registers.
81	 */
82	OR_REG(osh, &pci->command, 2);
83
84	/*
85	 * Enable the posted write flush scheme as follows:
86	 *
87	 * - Enable flush on any core register read
88	 * - Enable timeout on the flush
89	 * - Disable the interrupt mask when flushing
90	 *
91	 * This differs from the default setting only in that interrupts are
92	 * not masked.  Since posted writes are not flushed on interrupt, the
93	 * driver must explicitly request a flush in its interrupt handling
94	 * by reading a core register.
95	 */
96	W_REG(osh, &ocp->FlushStatusControl, 0x68);
97
98	/*
99	 * Determine whether the GbE is in GMII or RGMII mode.  This is
100	 * indicated in bit 16 of the SBTMStateHigh register, which is
101	 * part of the core-specific flags field.
102	 *
103	 * For GMII, bypass the Rx/Tx DLLs, i.e. add no delay to RXC/GTXC
104	 * within the core.  For RGMII, do not bypass the DLLs, resulting
105	 * in added delay for RXC/GTXC.  The SBTMStateLow register contains
106	 * the controls for doing this in the core-specific flags field:
107	 *
108	 *   bit 24 - Enable DLL controls
109	 *   bit 20 - Bypass Rx DLL
110	 *   bit 19 - Bypass Tx DLL
111	 */
112	statelow = R_REG(osh, &sb->sbtmstatelow);	/* DLL controls */
113	statehigh = R_REG(osh, &sb->sbtmstatehigh);	/* GMII/RGMII mode */
114	if ((statehigh & (1 << 16)) != 0)	/* RGMII */
115	{
116		statelow &= ~(1 << 20);		/* no Rx bypass (delay) */
117		statelow &= ~(1 << 19);		/* no Tx bypass (delay) */
118		*rgmii = TRUE;
119	}
120	else					/* GMII */
121	{
122		statelow |= (1 << 20);		/* Rx bypass (no delay) */
123		statelow |= (1 << 19);		/* Tx bypass (no delay) */
124		*rgmii = FALSE;
125	}
126	statelow |= (1 << 24);			/* enable DLL controls */
127	W_REG(osh, &sb->sbtmstatelow, statelow);
128
129	si_setcoreidx(sih, idx);
130}
131