1/*
2 * @TAG(OTHER_GPL)
3 */
4
5/*
6 * Micrel PHY drivers
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 * Copyright 2010-2011 Freescale Semiconductor, Inc.
24 * author Andy Fleming
25 *
26 */
27#include "config.h"
28#include "common.h"
29#include "micrel.h"
30#include "phy.h"
31
32#define CONFIG_PHY_MICREL_KSZ9021
33
34static struct phy_driver KSZ804_driver = {
35	.name = "Micrel KSZ804",
36	.uid = 0x221510,
37	.mask = 0xfffff0,
38	.features = PHY_BASIC_FEATURES,
39	.config = &genphy_config,
40	.startup = &genphy_startup,
41	.shutdown = &genphy_shutdown,
42};
43
44/* ksz9021 PHY Registers */
45#define MII_KSZ9021_EXTENDED_CTRL	0x0b
46#define MII_KSZ9021_EXTENDED_DATAW	0x0c
47#define MII_KSZ9021_EXTENDED_DATAR	0x0d
48#define MII_KSZ9021_PHY_CTL		0x1f
49#define MIIM_KSZ9021_PHYCTL_1000	(BIT(6))
50#define MIIM_KSZ9021_PHYCTL_100		(BIT(5))
51#define MIIM_KSZ9021_PHYCTL_10		(BIT(4))
52#define MIIM_KSZ9021_PHYCTL_DUPLEX	(BIT(3))
53
54#define CTRL1000_PREFER_MASTER		(BIT(10))
55#define CTRL1000_CONFIG_MASTER		(BIT(11))
56#define CTRL1000_MANUAL_CONFIG		(BIT(12))
57
58int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, uint16_t val)
59{
60	/* extended registers */
61	phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_CTRL, regnum | 0x8000);
62	return phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAW, val);
63}
64
65int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum)
66{
67	/* extended registers */
68	phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_CTRL, regnum);
69	return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAR);
70}
71
72/* Micrel ksz9021 */
73int ksz9021_config(struct phy_device *phydev)
74{
75	unsigned ctrl1000 = 0;
76	const unsigned master = CTRL1000_PREFER_MASTER |
77			CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG;
78	unsigned features = phydev->drv->features;
79
80	/* force master mode for 1000BaseT due to chip errata */
81	if (features & SUPPORTED_1000baseT_Half)
82		ctrl1000 |= ADVERTISE_1000HALF | master;
83	if (features & SUPPORTED_1000baseT_Full)
84		ctrl1000 |= ADVERTISE_1000FULL | master;
85	phydev->advertising = phydev->supported = features;
86	phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, ctrl1000);
87	genphy_config_aneg(phydev);
88	genphy_restart_aneg(phydev);
89	return 0;
90}
91
92void print_phyregs(struct phy_device *phydev){
93    int i;
94    printf("\n\nPHY config\n");
95    printf("\n\nIEEE\n");
96    for(i = 0; i < 16; i++){
97	    uint16_t val = phy_read(phydev, MDIO_DEVAD_NONE, i);
98        printf("%3d | 0x%04x\n", i, val);
99    }
100
101    printf("vendor\n");
102    for(i = 16; i < 32; i++){
103	    uint16_t val = phy_read(phydev, MDIO_DEVAD_NONE, i);
104        printf("%3d | 0x%04x\n", i, val);
105    }
106
107    printf("extended\n");
108    for(i = 257; i < 264; i++){
109	    uint16_t val = ksz9021_phy_extended_read(phydev, i);
110        printf("%3d | 0x%04x\n", i, val);
111    }
112    printf("\n\n");
113}
114
115int ksz9021_startup(struct phy_device *phydev)
116{
117	unsigned phy_ctl;
118	genphy_update_link(phydev);
119	phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_PHY_CTL);
120
121	if (phy_ctl & MIIM_KSZ9021_PHYCTL_DUPLEX){
122		phydev->duplex = DUPLEX_FULL;
123	}else{
124		phydev->duplex = DUPLEX_HALF;
125    }
126	if (phy_ctl & MIIM_KSZ9021_PHYCTL_1000){
127		phydev->speed = SPEED_1000;
128    }else if (phy_ctl & MIIM_KSZ9021_PHYCTL_100){
129		phydev->speed = SPEED_100;
130	}else if (phy_ctl & MIIM_KSZ9021_PHYCTL_10){
131		phydev->speed = SPEED_10;
132    }
133	return 0;
134}
135
136static struct phy_driver ksz9021_driver = {
137	.name = "Micrel ksz9021",
138	.uid  = 0x221610,
139	.mask = 0xfffff0,
140	.features = PHY_GBIT_FEATURES,
141	.config = &ksz9021_config,
142	.startup = &ksz9021_startup,
143	.shutdown = &genphy_shutdown,
144};
145
146int phy_micrel_init(void)
147{
148	phy_register(&KSZ804_driver);
149	phy_register(&ksz9021_driver);
150	return 0;
151}
152