1/*
2 * drivers/net/ibm_emac/ibm_emac_zmii.c
3 *
4 * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
5 *
6 * Copyright (c) 2004, 2005 Zultys Technologies.
7 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
8 *
9 * Based on original work by
10 *      Armin Kuster <akuster@mvista.com>
11 * 	Copyright 2001 MontaVista Softare Inc.
12 *
13 * This program is free software; you can redistribute  it and/or modify it
14 * under  the terms of  the GNU General  Public License as published by the
15 * Free Software Foundation;  either version 2 of the  License, or (at your
16 * option) any later version.
17 *
18 */
19#include <linux/kernel.h>
20#include <linux/ethtool.h>
21#include <asm/io.h>
22
23#include "ibm_emac_core.h"
24#include "ibm_emac_debug.h"
25
26/* ZMIIx_FER */
27#define ZMII_FER_MDI(idx)	(0x80000000 >> ((idx) * 4))
28#define ZMII_FER_MDI_ALL	(ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \
29				 ZMII_FER_MDI(2) | ZMII_FER_MDI(3))
30
31#define ZMII_FER_SMII(idx)	(0x40000000 >> ((idx) * 4))
32#define ZMII_FER_RMII(idx)	(0x20000000 >> ((idx) * 4))
33#define ZMII_FER_MII(idx)	(0x10000000 >> ((idx) * 4))
34
35/* ZMIIx_SSR */
36#define ZMII_SSR_SCI(idx)	(0x40000000 >> ((idx) * 4))
37#define ZMII_SSR_FSS(idx)	(0x20000000 >> ((idx) * 4))
38#define ZMII_SSR_SP(idx)	(0x10000000 >> ((idx) * 4))
39
40/* ZMII only supports MII, RMII and SMII
41 * we also support autodetection for backward compatibility
42 */
43static inline int zmii_valid_mode(int mode)
44{
45	return  mode == PHY_MODE_MII ||
46		mode == PHY_MODE_RMII ||
47		mode == PHY_MODE_SMII ||
48		mode == PHY_MODE_NA;
49}
50
51static inline const char *zmii_mode_name(int mode)
52{
53	switch (mode) {
54	case PHY_MODE_MII:
55		return "MII";
56	case PHY_MODE_RMII:
57		return "RMII";
58	case PHY_MODE_SMII:
59		return "SMII";
60	default:
61		BUG();
62	}
63}
64
65static inline u32 zmii_mode_mask(int mode, int input)
66{
67	switch (mode) {
68	case PHY_MODE_MII:
69		return ZMII_FER_MII(input);
70	case PHY_MODE_RMII:
71		return ZMII_FER_RMII(input);
72	case PHY_MODE_SMII:
73		return ZMII_FER_SMII(input);
74	default:
75		return 0;
76	}
77}
78
79static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode)
80{
81	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
82	struct zmii_regs __iomem *p;
83
84	ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode);
85
86	if (!dev) {
87		dev = kzalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL);
88		if (!dev) {
89			printk(KERN_ERR
90			       "zmii%d: couldn't allocate device structure!\n",
91			       ocpdev->def->index);
92			return -ENOMEM;
93		}
94		dev->mode = PHY_MODE_NA;
95
96		p = ioremap(ocpdev->def->paddr, sizeof(struct zmii_regs));
97		if (!p) {
98			printk(KERN_ERR
99			       "zmii%d: could not ioremap device registers!\n",
100			       ocpdev->def->index);
101			kfree(dev);
102			return -ENOMEM;
103		}
104		dev->base = p;
105		ocp_set_drvdata(ocpdev, dev);
106
107		/* We may need FER value for autodetection later */
108		dev->fer_save = in_be32(&p->fer);
109
110		/* Disable all inputs by default */
111		out_be32(&p->fer, 0);
112	} else
113		p = dev->base;
114
115	if (!zmii_valid_mode(*mode)) {
116		/* Probably an EMAC connected to RGMII,
117		 * but it still may need ZMII for MDIO
118		 */
119		goto out;
120	}
121
122	/* Autodetect ZMII mode if not specified.
123	 * This is only for backward compatibility with the old driver.
124	 * Please, always specify PHY mode in your board port to avoid
125	 * any surprises.
126	 */
127	if (dev->mode == PHY_MODE_NA) {
128		if (*mode == PHY_MODE_NA) {
129			u32 r = dev->fer_save;
130
131			ZMII_DBG("%d: autodetecting mode, FER = 0x%08x" NL,
132				 ocpdev->def->index, r);
133
134			if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1)))
135				dev->mode = PHY_MODE_MII;
136			else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1)))
137				dev->mode = PHY_MODE_RMII;
138			else
139				dev->mode = PHY_MODE_SMII;
140		} else
141			dev->mode = *mode;
142
143		printk(KERN_NOTICE "zmii%d: bridge in %s mode\n",
144		       ocpdev->def->index, zmii_mode_name(dev->mode));
145	} else {
146		/* All inputs must use the same mode */
147		if (*mode != PHY_MODE_NA && *mode != dev->mode) {
148			printk(KERN_ERR
149			       "zmii%d: invalid mode %d specified for input %d\n",
150			       ocpdev->def->index, *mode, input);
151			return -EINVAL;
152		}
153	}
154
155	/* Report back correct PHY mode,
156	 * it may be used during PHY initialization.
157	 */
158	*mode = dev->mode;
159
160	/* Enable this input */
161	out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input));
162      out:
163	++dev->users;
164	return 0;
165}
166
167int __init zmii_attach(void *emac)
168{
169	struct ocp_enet_private *dev = emac;
170	struct ocp_func_emac_data *emacdata = dev->def->additions;
171
172	if (emacdata->zmii_idx >= 0) {
173		dev->zmii_input = emacdata->zmii_mux;
174		dev->zmii_dev =
175		    ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_ZMII,
176				    emacdata->zmii_idx);
177		if (!dev->zmii_dev) {
178			printk(KERN_ERR "emac%d: unknown zmii%d!\n",
179			       dev->def->index, emacdata->zmii_idx);
180			return -ENODEV;
181		}
182		if (zmii_init
183		    (dev->zmii_dev, dev->zmii_input, &emacdata->phy_mode)) {
184			printk(KERN_ERR
185			       "emac%d: zmii%d initialization failed!\n",
186			       dev->def->index, emacdata->zmii_idx);
187			return -ENODEV;
188		}
189	}
190	return 0;
191}
192
193void __zmii_enable_mdio(struct ocp_device *ocpdev, int input)
194{
195	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
196	u32 fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL;
197
198	ZMII_DBG2("%d: mdio(%d)" NL, ocpdev->def->index, input);
199
200	out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input));
201}
202
203void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed)
204{
205	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
206	u32 ssr = in_be32(&dev->base->ssr);
207
208	ZMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed);
209
210	if (speed == SPEED_100)
211		ssr |= ZMII_SSR_SP(input);
212	else
213		ssr &= ~ZMII_SSR_SP(input);
214
215	out_be32(&dev->base->ssr, ssr);
216}
217
218void __zmii_fini(struct ocp_device *ocpdev, int input)
219{
220	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
221	BUG_ON(!dev || dev->users == 0);
222
223	ZMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input);
224
225	/* Disable this input */
226	out_be32(&dev->base->fer,
227		 in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input));
228
229	if (!--dev->users) {
230		/* Free everything if this is the last user */
231		ocp_set_drvdata(ocpdev, NULL);
232		iounmap(dev->base);
233		kfree(dev);
234	}
235}
236
237int __zmii_get_regs_len(struct ocp_device *ocpdev)
238{
239	return sizeof(struct emac_ethtool_regs_subhdr) +
240	    sizeof(struct zmii_regs);
241}
242
243void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf)
244{
245	struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
246	struct emac_ethtool_regs_subhdr *hdr = buf;
247	struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1);
248
249	hdr->version = 0;
250	hdr->index = ocpdev->def->index;
251	memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs));
252	return regs + 1;
253}
254