blob: 56191822fa26a74446a689bfa7911b1634d249e6 [file] [log] [blame]
Vitaly Bordug11b0bac2006-08-14 23:00:29 -07001/*
2 * drivers/net/phy/fixed.c
3 *
4 * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode.
5 *
6 * Author: Vitaly Bordug
7 *
8 * Copyright (c) 2006 MontaVista Software, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070016#include <linux/kernel.h>
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070017#include <linux/string.h>
18#include <linux/errno.h>
19#include <linux/unistd.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/netdevice.h>
25#include <linux/etherdevice.h>
26#include <linux/skbuff.h>
27#include <linux/spinlock.h>
28#include <linux/mm.h>
29#include <linux/module.h>
30#include <linux/mii.h>
31#include <linux/ethtool.h>
32#include <linux/phy.h>
Vitaly Bordug7c32f472007-08-10 14:05:16 -070033#include <linux/phy_fixed.h>
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070034
35#include <asm/io.h>
36#include <asm/irq.h>
37#include <asm/uaccess.h>
38
Vitaly Bordug7c32f472007-08-10 14:05:16 -070039/* we need to track the allocated pointers in order to free them on exit */
40static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT];
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070041
42/*-----------------------------------------------------------------------------
43 * If something weird is required to be done with link/speed,
44 * network driver is able to assign a function to implement this.
45 * May be useful for PHY's that need to be software-driven.
46 *-----------------------------------------------------------------------------*/
Vitaly Bordug7c32f472007-08-10 14:05:16 -070047int fixed_mdio_set_link_update(struct phy_device *phydev,
48 int (*link_update) (struct net_device *,
49 struct fixed_phy_status *))
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070050{
51 struct fixed_info *fixed;
52
Vitaly Bordug7c32f472007-08-10 14:05:16 -070053 if (link_update == NULL)
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070054 return -EINVAL;
55
Vitaly Bordug7c32f472007-08-10 14:05:16 -070056 if (phydev) {
57 if (phydev->bus) {
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070058 fixed = phydev->bus->priv;
59 fixed->link_update = link_update;
60 return 0;
61 }
62 }
63 return -EINVAL;
64}
Vitaly Bordug7c32f472007-08-10 14:05:16 -070065
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070066EXPORT_SYMBOL(fixed_mdio_set_link_update);
67
Vitaly Bordug7c32f472007-08-10 14:05:16 -070068struct fixed_info *fixed_mdio_get_phydev (int phydev_ind)
69{
70 if (phydev_ind >= MAX_PHY_AMNT)
71 return NULL;
72 return fixed_phy_ptrs[phydev_ind];
73}
74
75EXPORT_SYMBOL(fixed_mdio_get_phydev);
76
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070077/*-----------------------------------------------------------------------------
78 * This is used for updating internal mii regs from the status
79 *-----------------------------------------------------------------------------*/
Vitaly Bordug7c32f472007-08-10 14:05:16 -070080#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070081static int fixed_mdio_update_regs(struct fixed_info *fixed)
82{
83 u16 *regs = fixed->regs;
84 u16 bmsr = 0;
85 u16 bmcr = 0;
86
Vitaly Bordug7c32f472007-08-10 14:05:16 -070087 if (!regs) {
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070088 printk(KERN_ERR "%s: regs not set up", __FUNCTION__);
89 return -EINVAL;
90 }
91
Vitaly Bordug7c32f472007-08-10 14:05:16 -070092 if (fixed->phy_status.link)
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070093 bmsr |= BMSR_LSTATUS;
94
Vitaly Bordug7c32f472007-08-10 14:05:16 -070095 if (fixed->phy_status.duplex) {
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070096 bmcr |= BMCR_FULLDPLX;
97
Vitaly Bordug7c32f472007-08-10 14:05:16 -070098 switch (fixed->phy_status.speed) {
Vitaly Bordug11b0bac2006-08-14 23:00:29 -070099 case 100:
100 bmsr |= BMSR_100FULL;
101 bmcr |= BMCR_SPEED100;
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700102 break;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700103
104 case 10:
105 bmsr |= BMSR_10FULL;
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700106 break;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700107 }
108 } else {
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700109 switch (fixed->phy_status.speed) {
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700110 case 100:
111 bmsr |= BMSR_100HALF;
112 bmcr |= BMCR_SPEED100;
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700113 break;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700114
115 case 10:
116 bmsr |= BMSR_100HALF;
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700117 break;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700118 }
119 }
120
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700121 regs[MII_BMCR] = bmcr;
122 regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700123
124 return 0;
125}
126
127static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location)
128{
129 struct fixed_info *fixed = bus->priv;
130
131 /* if user has registered link update callback, use it */
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700132 if (fixed->phydev)
133 if (fixed->phydev->attached_dev) {
134 if (fixed->link_update) {
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700135 fixed->link_update(fixed->phydev->attached_dev,
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700136 &fixed->phy_status);
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700137 fixed_mdio_update_regs(fixed);
138 }
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700139 }
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700140
141 if ((unsigned int)location >= fixed->regs_num)
142 return -1;
143 return fixed->regs[location];
144}
145
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700146static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location,
147 u16 val)
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700148{
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700149 /* do nothing for now */
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700150 return 0;
151}
152
153static int fixed_mii_reset(struct mii_bus *bus)
154{
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700155 /*nothing here - no way/need to reset it */
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700156 return 0;
157}
Denver Gingerich239dc572007-05-23 14:34:43 -0700158#endif
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700159
160static int fixed_config_aneg(struct phy_device *phydev)
161{
162 /* :TODO:03/13/2006 09:45:37 PM::
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700163 The full autoneg funcionality can be emulated,
164 but no need to have anything here for now
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700165 */
166 return 0;
167}
168
169/*-----------------------------------------------------------------------------
170 * the manual bind will do the magic - with phy_id_mask == 0
171 * match will never return true...
172 *-----------------------------------------------------------------------------*/
173static struct phy_driver fixed_mdio_driver = {
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700174 .name = "Fixed PHY",
175#ifdef CONFIG_FIXED_MII_1000_FDX
176 .features = PHY_GBIT_FEATURES,
177#else
178 .features = PHY_BASIC_FEATURES,
179#endif
180 .config_aneg = fixed_config_aneg,
181 .read_status = genphy_read_status,
182 .driver = { .owner = THIS_MODULE, },
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700183};
184
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700185static void fixed_mdio_release(struct device *dev)
186{
187 struct phy_device *phydev = container_of(dev, struct phy_device, dev);
188 struct mii_bus *bus = phydev->bus;
189 struct fixed_info *fixed = bus->priv;
190
191 kfree(phydev);
192 kfree(bus->dev);
193 kfree(bus);
194 kfree(fixed->regs);
195 kfree(fixed);
196}
197
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700198/*-----------------------------------------------------------------------------
199 * This func is used to create all the necessary stuff, bind
200 * the fixed phy driver and register all it on the mdio_bus_type.
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700201 * speed is either 10 or 100 or 1000, duplex is boolean.
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700202 * number is used to create multiple fixed PHYs, so that several devices can
203 * utilize them simultaneously.
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700204 *
205 * The device on mdio bus will look like [bus_id]:[phy_id],
206 * bus_id = number
207 * phy_id = speed+duplex.
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700208 *-----------------------------------------------------------------------------*/
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700209#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
210struct fixed_info *fixed_mdio_register_device(
211 int bus_id, int speed, int duplex, u8 phy_id)
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700212{
213 struct mii_bus *new_bus;
214 struct fixed_info *fixed;
215 struct phy_device *phydev;
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700216 int err;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700217
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700218 struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700219
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700220 if (dev == NULL)
221 goto err_dev_alloc;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700222
223 new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
224
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700225 if (new_bus == NULL)
226 goto err_bus_alloc;
227
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700228 fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);
229
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700230 if (fixed == NULL)
231 goto err_fixed_alloc;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700232
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700233 fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL);
234 if (NULL == fixed->regs)
235 goto err_fixed_regs_alloc;
236
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700237 fixed->regs_num = MII_REGS_NUM;
238 fixed->phy_status.speed = speed;
239 fixed->phy_status.duplex = duplex;
240 fixed->phy_status.link = 1;
241
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700242 new_bus->name = "Fixed MII Bus";
243 new_bus->read = &fixed_mii_read;
244 new_bus->write = &fixed_mii_write;
245 new_bus->reset = &fixed_mii_reset;
246 /*set up workspace */
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700247 fixed_mdio_update_regs(fixed);
248 new_bus->priv = fixed;
249
250 new_bus->dev = dev;
251 dev_set_drvdata(dev, new_bus);
252
253 /* create phy_device and register it on the mdio bus */
254 phydev = phy_device_create(new_bus, 0, 0);
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700255 if (phydev == NULL)
256 goto err_phy_dev_create;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700257
258 /*
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700259 * Put the phydev pointer into the fixed pack so that bus read/write
260 * code could be able to access for instance attached netdev. Well it
261 * doesn't have to do so, only in case of utilizing user-specified
262 * link-update...
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700263 */
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700264
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700265 fixed->phydev = phydev;
266 phydev->speed = speed;
267 phydev->duplex = duplex;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700268
Andy Fleminga9b14972006-10-19 19:52:26 -0500269 phydev->irq = PHY_IGNORE_INTERRUPT;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700270 phydev->dev.bus = &mdio_bus_type;
271
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700272 snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
273 PHY_ID_FMT, bus_id, phy_id);
274
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700275 phydev->bus = new_bus;
276
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700277 phydev->dev.driver = &fixed_mdio_driver.driver;
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700278 phydev->dev.release = fixed_mdio_release;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700279 err = phydev->dev.driver->probe(&phydev->dev);
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700280 if (err < 0) {
281 printk(KERN_ERR "Phy %s: problems with fixed driver\n",
282 phydev->dev.bus_id);
283 goto err_out;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700284 }
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700285 err = device_register(&phydev->dev);
286 if (err) {
287 printk(KERN_ERR "Phy %s failed to register\n",
288 phydev->dev.bus_id);
289 goto err_out;
290 }
291 //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX
292 return fixed;
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700293
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700294err_out:
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700295 kfree(phydev);
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700296err_phy_dev_create:
297 kfree(fixed->regs);
298err_fixed_regs_alloc:
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700299 kfree(fixed);
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700300err_fixed_alloc:
301 kfree(new_bus);
302err_bus_alloc:
303 kfree(dev);
304err_dev_alloc:
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700305
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700306 return NULL;
307
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700308}
Denver Gingerich239dc572007-05-23 14:34:43 -0700309#endif
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700310
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700311MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
312MODULE_AUTHOR("Vitaly Bordug");
313MODULE_LICENSE("GPL");
314
315static int __init fixed_init(void)
316{
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700317 int cnt = 0;
318 int i;
319/* register on the bus... Not expected to be matched
320 * with anything there...
321 *
322 */
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700323 phy_driver_register(&fixed_mdio_driver);
324
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700325/* We will create several mdio devices here, and will bound the upper
326 * driver to them.
327 *
328 * Then the external software can lookup the phy bus by searching
329 * for 0:101, to be connected to the virtual 100M Fdx phy.
330 *
331 * In case several virtual PHYs required, the bus_id will be in form
332 * [num]:[duplex]+[speed], which make it able even to define
333 * driver-specific link control callback, if for instance PHY is
334 * completely SW-driven.
335 */
336 for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) {
337#ifdef CONFIG_FIXED_MII_1000_FDX
338 fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i);
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700339#endif
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700340#ifdef CONFIG_FIXED_MII_100_FDX
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700341 fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i);
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700342#endif
Vitaly Bordugb1f54ba2007-01-27 00:00:04 -0800343#ifdef CONFIG_FIXED_MII_10_FDX
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700344 fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i);
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700345#endif
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700346 }
347
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700348 return 0;
349}
350
351static void __exit fixed_exit(void)
352{
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700353 int i;
354
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700355 phy_driver_unregister(&fixed_mdio_driver);
Vitaly Bordug7c32f472007-08-10 14:05:16 -0700356 for (i=0; i < MAX_PHY_AMNT; i++)
357 if ( fixed_phy_ptrs[i] )
358 device_unregister(&fixed_phy_ptrs[i]->phydev->dev);
Vitaly Bordug11b0bac2006-08-14 23:00:29 -0700359}
360
361module_init(fixed_init);
362module_exit(fixed_exit);