blob: 788b6efd1763ef5b2aa7428b46a90134cfb964de [file] [log] [blame]
Yinghai Luc65bd562007-02-01 00:10:05 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Yinghai Luc65bd562007-02-01 00:10:05 +00003 *
4 * Copyright (C) 2004 Tyan Computer
5 * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer.
6 * Copyright (C) 2006,2007 AMD
7 * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
Yinghai Luc65bd562007-02-01 00:10:05 +000018 */
19
20#include <console/console.h>
21#include <device/device.h>
22#include <device/smbus.h>
23#include <device/pci.h>
24#include <device/pci_ids.h>
25#include <device/pci_ops.h>
26#include <arch/io.h>
Carl-Daniel Hailfingereb30bf82008-12-22 16:19:02 +000027#include <delay.h>
Yinghai Luc65bd562007-02-01 00:10:05 +000028#include "mcp55.h"
29
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080030static int phy_read(u8 *base, unsigned phy_addr, unsigned phy_reg)
Yinghai Luc65bd562007-02-01 00:10:05 +000031{
Stefan Reinauer8b547b12010-03-30 09:56:35 +000032 u32 dword;
Yinghai Luc65bd562007-02-01 00:10:05 +000033 unsigned loop = 0x100;
Yinghai Luc65bd562007-02-01 00:10:05 +000034
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000035 write32(base + 0x190, 0x8000); /* Clear MDIO lock bit. */
36 mdelay(1);
37 dword = read32(base + 0x190);
38 if (dword & (1 << 15))
39 return -1;
40
41 write32(base + 0x180, 1);
42 write32(base + 0x190, (phy_addr << 5) | (phy_reg));
43 do {
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000044 dword = read32(base + 0x190);
Elyes HAOUAS581fe582018-04-26 09:57:07 +020045 if (--loop == 0)
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000046 return -4;
47 } while ((dword & (1 << 15)));
Yinghai Luc65bd562007-02-01 00:10:05 +000048
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000049 dword = read32(base + 0x180);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000050 if (dword & 1)
51 return -3;
Yinghai Luc65bd562007-02-01 00:10:05 +000052
Stefan Reinauer9fe4d792010-01-16 17:53:38 +000053 dword = read32(base + 0x194);
Yinghai Luc65bd562007-02-01 00:10:05 +000054
55 return dword;
Yinghai Luc65bd562007-02-01 00:10:05 +000056}
57
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080058static void phy_detect(u8 *base)
Yinghai Luc65bd562007-02-01 00:10:05 +000059{
Stefan Reinauer8b547b12010-03-30 09:56:35 +000060 u32 dword;
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000061 int i, val;
Yinghai Luc65bd562007-02-01 00:10:05 +000062 unsigned id;
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000063
64 dword = read32(base + 0x188);
65 dword &= ~(1 << 20);
66 write32(base + 0x188, dword);
Yinghai Luc65bd562007-02-01 00:10:05 +000067
68 phy_read(base, 0, 1);
69
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000070 for (i = 1; i <= 32; i++) {
Yinghai Luc65bd562007-02-01 00:10:05 +000071 int phyaddr = i & 0x1f;
72 val = phy_read(base, phyaddr, 1);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000073 if (val < 0)
74 continue;
Martin Rotheec34022017-01-11 09:43:52 -070075 if ((val & 0xffff) == 0xffff)
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000076 continue;
77 if ((val & 0xffff) == 0)
78 continue;
79 if (!(val & 1))
80 break; /* Ethernet PHY */
81
Yinghai Luc65bd562007-02-01 00:10:05 +000082 val = phy_read(base, phyaddr, 3);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000083 if (val < 0 || val == 0xffff)
84 continue;
Yinghai Luc65bd562007-02-01 00:10:05 +000085 id = val & 0xfc00;
86 val = phy_read(base, phyaddr, 2);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000087 if (val < 0 || val == 0xffff)
88 continue;
89 id |= ((val & 0xffff) << 16);
90 printk(BIOS_DEBUG, "MCP55 MAC PHY ID 0x%08x PHY ADDR %d\n",
91 id, i);
92// if ((id == 0xe0180000) || (id == 0x0032cc00))
Yinghai Luc65bd562007-02-01 00:10:05 +000093 break;
94 }
95
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000096 if (i > 32)
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +000097 printk(BIOS_DEBUG, "MCP55 MAC PHY not found\n");
Yinghai Luc65bd562007-02-01 00:10:05 +000098}
Stefan Reinauer870f0132009-04-28 14:49:50 +000099
Yinghai Luc65bd562007-02-01 00:10:05 +0000100static void nic_init(struct device *dev)
101{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800102 u8 *base;
103 u32 mac_h = 0, mac_l = 0;
Yinghai Luc65bd562007-02-01 00:10:05 +0000104 int eeprom_valid = 0;
105 struct southbridge_nvidia_mcp55_config *conf;
Stefan Reinauer8b547b12010-03-30 09:56:35 +0000106 static u32 nic_index = 0;
Yinghai Luc65bd562007-02-01 00:10:05 +0000107 struct resource *res;
108
109 res = find_resource(dev, 0x10);
110
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000111 if (!res)
112 return;
Yinghai Luc65bd562007-02-01 00:10:05 +0000113
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800114 base = res2mmio(res, 0, 0);
Yinghai Luc65bd562007-02-01 00:10:05 +0000115
116 phy_detect(base);
117
118#define NvRegPhyInterface 0xC0
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000119#define PHY_RGMII 0x10000000
Yinghai Luc65bd562007-02-01 00:10:05 +0000120
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000121 write32(base + NvRegPhyInterface, PHY_RGMII);
Yinghai Luc65bd562007-02-01 00:10:05 +0000122
123 conf = dev->chip_info;
124
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000125 if (conf->mac_eeprom_smbus != 0) {
Yinghai Luc65bd562007-02-01 00:10:05 +0000126// read MAC address from EEPROM at first
127 struct device *dev_eeprom;
128 dev_eeprom = dev_find_slot_on_smbus(conf->mac_eeprom_smbus, conf->mac_eeprom_addr);
129
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200130 if (dev_eeprom) {
Yinghai Luc65bd562007-02-01 00:10:05 +0000131 // if that is valid we will use that
132 unsigned char dat[6];
133 int status;
134 int i;
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200135 for (i=0;i<6;i++) {
Yinghai Luc65bd562007-02-01 00:10:05 +0000136 status = smbus_read_byte(dev_eeprom, i);
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200137 if (status < 0) break;
Yinghai Luc65bd562007-02-01 00:10:05 +0000138 dat[i] = status & 0xff;
139 }
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200140 if (status >= 0) {
Yinghai Luc65bd562007-02-01 00:10:05 +0000141 mac_l = 0;
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200142 for (i=3;i>=0;i--) {
Yinghai Luc65bd562007-02-01 00:10:05 +0000143 mac_l <<= 8;
144 mac_l += dat[i];
145 }
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200146 if (mac_l != 0xffffffff) {
Yinghai Luc65bd562007-02-01 00:10:05 +0000147 mac_l += nic_index;
148 mac_h = 0;
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200149 for (i=5;i>=4;i--) {
Yinghai Luc65bd562007-02-01 00:10:05 +0000150 mac_h <<= 8;
151 mac_h += dat[i];
152 }
153 eeprom_valid = 1;
154 }
155 }
156 }
157 }
158// if that is invalid we will read that from romstrap
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200159 if (!eeprom_valid) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800160 u32 *mac_pos;
Patrick Georgiea9f3082015-03-27 13:50:11 +0100161 mac_pos = (u32 *)0xffffffd0; // refer to romstrap.inc and romstrap.ld
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000162 mac_l = read32(mac_pos) + nic_index; // overflow?
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800163 mac_h = read32(mac_pos + 1);
Yinghai Luc65bd562007-02-01 00:10:05 +0000164
165 }
166#if 1
167// set that into NIC MMIO
168#define NvRegMacAddrA 0xA8
169#define NvRegMacAddrB 0xAC
Stefan Reinauer9fe4d792010-01-16 17:53:38 +0000170 write32(base + NvRegMacAddrA, mac_l);
171 write32(base + NvRegMacAddrB, mac_h);
Yinghai Luc65bd562007-02-01 00:10:05 +0000172#else
173// set that into NIC
174 pci_write_config32(dev, 0xa8, mac_l);
175 pci_write_config32(dev, 0xac, mac_h);
176#endif
177
178 nic_index++;
Yinghai Luc65bd562007-02-01 00:10:05 +0000179}
180
Yinghai Luc65bd562007-02-01 00:10:05 +0000181static struct device_operations nic_ops = {
182 .read_resources = pci_dev_read_resources,
183 .set_resources = pci_dev_set_resources,
184 .enable_resources = pci_dev_enable_resources,
185 .init = nic_init,
186 .scan_bus = 0,
187// .enable = mcp55_enable,
Jonathan Kollaschdca8b1b2010-10-29 20:40:06 +0000188 .ops_pci = &mcp55_pci_ops,
Yinghai Luc65bd562007-02-01 00:10:05 +0000189};
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +0000190static const struct pci_driver nic_driver __pci_driver = {
Yinghai Luc65bd562007-02-01 00:10:05 +0000191 .ops = &nic_ops,
192 .vendor = PCI_VENDOR_ID_NVIDIA,
193 .device = PCI_DEVICE_ID_NVIDIA_MCP55_NIC,
194};
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +0000195static const struct pci_driver nic_bridge_driver __pci_driver = {
Yinghai Luc65bd562007-02-01 00:10:05 +0000196 .ops = &nic_ops,
197 .vendor = PCI_VENDOR_ID_NVIDIA,
198 .device = PCI_DEVICE_ID_NVIDIA_MCP55_NIC_BRIDGE,
199};