I.MX6 PHY fixup 调用流程 hacking

时间:2021-11-26 09:24:57
/**********************************************************************************
* I.MX6 PHY fixup 调用流程 hacking
* 说明:
* 跟一下i.MX6中对PHY进行fixup的代码是如何被调用的。
*
* 2017-4-14 深圳 龙华民治樟坑村 曾剑锋
********************************************************************************
*/
static struct platform_driver fec_driver = { <-----+
.driver
= { |
.name
= DRIVER_NAME, |
.owner
= THIS_MODULE, |
.pm
= &fec_pm_ops, |
.of_match_table
= fec_dt_ids, |
},
|
.id_table
= fec_devtype, ---------*-+
.probe
= fec_probe, | |
.remove
= fec_drv_remove, | |
};
| |
| |
module_platform_driver(fec_driver);
---------+ |
|
MODULE_ALIAS(
"platform:"DRIVER_NAME); |
MODULE_LICENSE(
"GPL"); |
|
static int |
fec_probe(
struct platform_device *pdev) <----------+
{
struct fec_enet_private *fep;
struct fec_platform_data *pdata;
struct net_device *ndev;
int i, irq, ret = 0;
struct resource *r;
const struct of_device_id *of_id;
static int dev_id;
struct device_node *np = pdev->dev.of_node, *phy_node;
int num_tx_qs;
int num_rx_qs;

fec_enet_get_queue_num(pdev,
&num_tx_qs, &num_rx_qs);

/* Init network device */
ndev
= alloc_etherdev_mqs(sizeof(struct fec_enet_private),
num_tx_qs, num_rx_qs);
if (!ndev)
return -ENOMEM;

SET_NETDEV_DEV(ndev,
&pdev->dev);

/* setup board info structure */
fep
= netdev_priv(ndev);

of_id
= of_match_device(fec_dt_ids, &pdev->dev);
if (of_id)
pdev
->id_entry = of_id->data;
fep
->quirks = pdev->id_entry->driver_data;

fep
->netdev = ndev;
fep
->num_rx_queues = num_rx_qs;
fep
->num_tx_queues = num_tx_qs;

#if !defined(CONFIG_M5272)
/* default enable pause frame auto negotiation */
if (fep->quirks & FEC_QUIRK_HAS_GBIT)
fep
->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
#endif

/* Select default pin state */
pinctrl_pm_select_default_state(
&pdev->dev);

r
= platform_get_resource(pdev, IORESOURCE_MEM, 0);
fep
->hwp = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(fep->hwp)) {
ret
= PTR_ERR(fep->hwp);
goto failed_ioremap;
}

fep
->pdev = pdev;
fep
->dev_id = dev_id++;

platform_set_drvdata(pdev, ndev);

fec_enet_of_parse_stop_mode(pdev);

if (of_get_property(np, "fsl,magic-packet", NULL))
fep
->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;

phy_node
= of_parse_phandle(np, "phy-handle", 0);
if (!phy_node && of_phy_is_fixed_link(np)) {
ret
= of_phy_register_fixed_link(np);
if (ret < 0) {
dev_err(
&pdev->dev,
"broken fixed-link specification\n");
goto failed_phy;
}
phy_node
= of_node_get(np);
}
fep
->phy_node = phy_node;

ret
= of_get_phy_mode(pdev->dev.of_node);
if (ret < 0) {
pdata
= dev_get_platdata(&pdev->dev);
if (pdata)
fep
->phy_interface = pdata->phy;
else
fep
->phy_interface = PHY_INTERFACE_MODE_MII;
}
else {
fep
->phy_interface = ret;
}

fep
->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(fep->clk_ipg)) {
ret
= PTR_ERR(fep->clk_ipg);
goto failed_clk;
}

fep
->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(fep->clk_ahb)) {
ret
= PTR_ERR(fep->clk_ahb);
goto failed_clk;
}

fep
->itr_clk_rate = clk_get_rate(fep->clk_ahb);

/* enet_out is optional, depends on board */
fep
->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");
if (IS_ERR(fep->clk_enet_out))
fep
->clk_enet_out = NULL;

fep
->ptp_clk_on = false;
mutex_init(
&fep->ptp_clk_mutex);

/* clk_ref is optional, depends on board */
fep
->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
if (IS_ERR(fep->clk_ref))
fep
->clk_ref = NULL;

fep
->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
fep
->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
if (IS_ERR(fep->clk_ptp)) {
fep
->clk_ptp = NULL;
fep
->bufdesc_ex = false;
}

pm_runtime_enable(
&pdev->dev);
ret
= fec_enet_clk_enable(ndev, true);
if (ret)
goto failed_clk;

fep
->reg_phy = devm_regulator_get(&pdev->dev, "phy");
if (!IS_ERR(fep->reg_phy)) {
ret
= regulator_enable(fep->reg_phy);
if (ret) {
dev_err(
&pdev->dev,
"Failed to enable phy regulator: %d\n", ret);
goto failed_regulator;
}
}
else {
fep
->reg_phy = NULL;
}

fec_reset_phy(pdev);

if (fep->bufdesc_ex)
fec_ptp_init(pdev);

ret
= fec_enet_init(ndev); ----------------------------+
if (ret) |
goto failed_init; |
|
for (i = 0; i < FEC_IRQ_NUM; i++) { |
irq
= platform_get_irq(pdev, i); |
if (irq < 0) { |
if (i) |
break; |
ret
= irq; |
goto failed_irq; |
}
|
ret
= devm_request_irq(&pdev->dev, irq, fec_enet_interrupt, |
0, pdev->name, ndev); |
if (ret) |
goto failed_irq; |
|
fep
->irq[i] = irq; |
}
|
|
ret
= of_property_read_u32(np, "fsl,wakeup_irq", &irq); |
if (!ret && irq < FEC_IRQ_NUM) |
fep
->wake_irq = fep->irq[irq]; |
else |
fep
->wake_irq = fep->irq[0]; |
|
init_completion(
&fep->mdio_done); |
ret
= fec_enet_mii_init(pdev); |
if (ret) |
goto failed_mii_init; |
|
/* Carrier starts down, phylib will bring it up */ |
netif_carrier_off(ndev);
|
fec_enet_clk_enable(ndev,
false); |
pinctrl_pm_select_sleep_state(
&pdev->dev); |
|
ret
= register_netdev(ndev); |
if (ret) |
goto failed_register; |
|
device_init_wakeup(
&ndev->dev, fep->wol_flag & |
FEC_WOL_HAS_MAGIC_PACKET);
|
|
if (fep->bufdesc_ex && fep->ptp_clock) |
netdev_info(ndev,
"registered PHC device %d\n", fep->dev_id); |
|
fep
->rx_copybreak = COPYBREAK_DEFAULT; |
INIT_WORK(
&fep->tx_timeout_work, fec_enet_timeout_work); |
return 0; |
|
failed_register:
|
fec_enet_mii_remove(fep);
|
failed_mii_init:
|
failed_irq:
|
failed_init:
|
if (fep->reg_phy) |
regulator_disable(fep
->reg_phy); |
failed_regulator:
|
fec_enet_clk_enable(ndev,
false); |
failed_clk:
|
failed_phy:
|
of_node_put(phy_node);
|
failed_ioremap:
|
free_netdev(ndev);
|
|
return ret; |
}
|
|
/* |
* XXX: We need to clean up on failure exits here. |
* |
*/ |
static int fec_enet_init(struct net_device *ndev) <-----------------+
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct fec_enet_priv_tx_q *txq;
struct fec_enet_priv_rx_q *rxq;
struct bufdesc *cbd_base;
dma_addr_t bd_dma;
int bd_size;
unsigned
int i;

#if defined(CONFIG_ARM)
fep
->rx_align = 0xf;
fep
->tx_align = 0xf;
#else
fep
->rx_align = 0x3;
fep
->tx_align = 0x3;
#endif

fec_enet_alloc_queue(ndev);

if (fep->bufdesc_ex)
fep
->bufdesc_size = sizeof(struct bufdesc_ex);
else
fep
->bufdesc_size = sizeof(struct bufdesc);
bd_size
= (fep->total_tx_ring_size + fep->total_rx_ring_size) *
fep
->bufdesc_size;

/* Allocate memory for buffer descriptors. */
cbd_base
= dma_alloc_coherent(NULL, bd_size, &bd_dma,
GFP_KERNEL);
if (!cbd_base) {
return -ENOMEM;
}

memset(cbd_base,
0, bd_size);

/* Get the Ethernet address */
fec_get_mac(ndev);
/* make sure MAC we just acquired is programmed into the hw */
fec_set_mac_address(ndev, NULL);

/* Set receive and transmit descriptor base. */
for (i = 0; i < fep->num_rx_queues; i++) {
rxq
= fep->rx_queue[i];
rxq
->index = i;
rxq
->rx_bd_base = (struct bufdesc *)cbd_base;
rxq
->bd_dma = bd_dma;
if (fep->bufdesc_ex) {
bd_dma
+= sizeof(struct bufdesc_ex) * rxq->rx_ring_size;
cbd_base
= (struct bufdesc *)
(((
struct bufdesc_ex *)cbd_base) + rxq->rx_ring_size);
}
else {
bd_dma
+= sizeof(struct bufdesc) * rxq->rx_ring_size;
cbd_base
+= rxq->rx_ring_size;
}
}

for (i = 0; i < fep->num_tx_queues; i++) {
txq
= fep->tx_queue[i];
txq
->index = i;
txq
->tx_bd_base = (struct bufdesc *)cbd_base;
txq
->bd_dma = bd_dma;
if (fep->bufdesc_ex) {
bd_dma
+= sizeof(struct bufdesc_ex) * txq->tx_ring_size;
cbd_base
= (struct bufdesc *)
(((
struct bufdesc_ex *)cbd_base) + txq->tx_ring_size);
}
else {
bd_dma
+= sizeof(struct bufdesc) * txq->tx_ring_size;
cbd_base
+= txq->tx_ring_size;
}
}


/* The FEC Ethernet specific entries in the device structure */
ndev
->watchdog_timeo = TX_TIMEOUT;
ndev
->netdev_ops = &fec_netdev_ops; --------------------+
ndev
->ethtool_ops = &fec_enet_ethtool_ops; |
|
writel(FEC_RX_DISABLED_IMASK, fep
->hwp + FEC_IMASK); |
netif_napi_add(ndev,
&fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT); |
|
if (fep->quirks & FEC_QUIRK_HAS_VLAN) |
/* enable hw VLAN support */ |
ndev
->features |= NETIF_F_HW_VLAN_CTAG_RX; |
|
if (fep->quirks & FEC_QUIRK_HAS_CSUM) { |
ndev
->gso_max_segs = FEC_MAX_TSO_SEGS; |
|
/* enable hw accelerator */ |
ndev
->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
| NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO); |
fep
->csum_flags |= FLAG_RX_CSUM_ENABLED; |
}
|
|
if (fep->quirks & FEC_QUIRK_HAS_AVB) { |
fep
->tx_align = 0; |
fep
->rx_align = 0x3f; |
}
|
|
ndev
->hw_features = ndev->features; |
|
fec_restart(ndev);
|
|
return 0; |
}
|
|
static const struct net_device_ops fec_netdev_ops = { <-----------+
.ndo_open
= fec_enet_open, ---------+
.ndo_stop
= fec_enet_close, |
.ndo_start_xmit
= fec_enet_start_xmit, |
.ndo_select_queue
= fec_enet_select_queue, |
.ndo_set_rx_mode
= set_multicast_list, |
.ndo_change_mtu
= eth_change_mtu, |
.ndo_validate_addr
= eth_validate_addr, |
.ndo_tx_timeout
= fec_timeout, |
.ndo_set_mac_address
= fec_set_mac_address, |
.ndo_do_ioctl
= fec_enet_ioctl, |
#ifdef CONFIG_NET_POLL_CONTROLLER
|
.ndo_poll_controller
= fec_poll_controller, |
#endif |
.ndo_set_features
= fec_set_features, |
};
|
|
static int |
fec_enet_open(
struct net_device *ndev) <--------+
{
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep
->pdev);
int ret;

pinctrl_pm_select_default_state(
&fep->pdev->dev);
ret
= fec_enet_clk_enable(ndev, true);
if (ret)
return ret;

/* I should reset the ring buffers here, but I don't yet know
* a simple way to do that.
*/

ret
= fec_enet_alloc_buffers(ndev);
if (ret)
goto err_enet_alloc;

/* Init MAC firstly for suspend/resume with megafix off case */
fec_restart(ndev);

/* Probe and connect to PHY when open the interface */
ret
= fec_enet_mii_probe(ndev); -----+
if (ret) |
goto err_enet_mii_probe; |
|
napi_enable(
&fep->napi); |
phy_start(fep
->phy_dev); |
netif_tx_start_all_queues(ndev);
|
|
pm_runtime_get_sync(ndev
->dev.parent); |
if ((id_entry->driver_data & FEC_QUIRK_BUG_WAITMODE) && |
!fec_enet_irq_workaround(fep)) |
pm_qos_add_request(
&ndev->pm_qos_req, |
PM_QOS_CPU_DMA_LATENCY,
|
0); |
else |
pm_qos_add_request(
&ndev->pm_qos_req, |
PM_QOS_CPU_DMA_LATENCY,
|
PM_QOS_DEFAULT_VALUE);
|
|
device_set_wakeup_enable(
&ndev->dev, fep->wol_flag & |
FEC_WOL_FLAG_ENABLE);
|
fep
->miibus_up_failed = false; |
|
return 0; |
|
err_enet_mii_probe:
|
fec_enet_free_buffers(ndev);
|
err_enet_alloc:
|
fep
->miibus_up_failed = true; |
if (!fep->mii_bus_share) |
pinctrl_pm_select_sleep_state(
&fep->pdev->dev); |
return ret; |
}
|
|
static int fec_enet_mii_probe(struct net_device *ndev) <----+
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phy_dev = NULL;
char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3];
int phy_id;
int dev_id = fep->dev_id;

fep
->phy_dev = NULL;

if (fep->phy_node) {
phy_dev
= of_phy_connect(ndev, fep->phy_node,
&fec_enet_adjust_link, 0,
fep
->phy_interface);
if (!phy_dev)
return -ENODEV;
}
else {
/* check for attached phy */
for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {
if ((fep->mii_bus->phy_mask & (1 << phy_id)))
continue;
if (fep->mii_bus->phy_map[phy_id] == NULL)
continue;
if (fep->mii_bus->phy_map[phy_id]->phy_id == 0)
continue;
if (dev_id--)
continue;
strlcpy(mdio_bus_id, fep
->mii_bus->id, MII_BUS_ID_SIZE);
break;
}

if (phy_id >= PHY_MAX_ADDR) {
netdev_info(ndev,
"no PHY, assuming direct connection to switch\n");
strlcpy(mdio_bus_id,
"fixed-0", MII_BUS_ID_SIZE);
phy_id
= 0;
}

snprintf(phy_name,
sizeof(phy_name),
PHY_ID_FMT, mdio_bus_id, phy_id);
phy_dev
= phy_connect(ndev, phy_name, &fec_enet_adjust_link, ---------------+
fep
->phy_interface); |
}
|
|
if (IS_ERR(phy_dev)) { |
netdev_err(ndev,
"could not attach to PHY\n"); |
return PTR_ERR(phy_dev); |
}
|
|
/* mask with MAC supported features */ |
if (fep->quirks & FEC_QUIRK_HAS_GBIT) { |
phy_dev
->supported &= PHY_GBIT_FEATURES; |
// phy_dev->supported &= ~SUPPORTED_1000baseT_Half; |
phy_dev->supported |= SUPPORTED_Pause; |
// phy_dev->supported |= SUPPORTED_1000baseT_Half; |
printk("FEC_QUIRK_HAS_GBIT\n"); |
#if !defined(CONFIG_M5272) |
phy_dev
->supported |= SUPPORTED_Pause; |
#endif |
phy_dev
->advertising = phy_dev->supported; |
}
|
else |
{
|
printk(
"PHY_BASIC_FEATURES\n"); |
// phy_dev->supported &= PHY_BASIC_FEATURES; |
phy_dev->advertising = phy_dev->supported & PHY_BASIC_FEATURES; |
}
|
// phy_dev->advertising = phy_dev->supported; |
|
fep
->phy_dev = phy_dev; |
fep
->link = 0; |
fep
->full_duplex = 0; |
|
netdev_info(ndev,
"Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", |
fep
->phy_dev->drv->name, dev_name(&fep->phy_dev->dev), |
fep
->phy_dev->irq); |
|
return 0; |
}
|
|
struct phy_device *phy_connect(struct net_device *dev, const char *bus_id, <--------+
void (*handler)(struct net_device *),
phy_interface_t
interface)
{
struct phy_device *phydev;
struct device *d;
int rc;

/* Search the list of PHY devices on the mdio bus for the
* PHY with the requested name
*/
d
= bus_find_device_by_name(&mdio_bus_type, NULL, bus_id);
if (!d) {
pr_err(
"PHY %s not found\n", bus_id);
return ERR_PTR(-ENODEV);
}
phydev
= to_phy_device(d);

rc
= phy_connect_direct(dev, phydev, handler, interface); --------------+
if (rc) |
return ERR_PTR(rc); |
|
return phydev; |
}
|
EXPORT_SYMBOL(phy_connect);
|
|
int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, <----+
void (*handler)(struct net_device *),
phy_interface_t
interface)
{
int rc;

rc
= phy_attach_direct(dev, phydev, phydev->dev_flags, interface); --------+
if (rc) |
return rc; |
|
phy_prepare_link(phydev, handler);
|
phy_start_machine(phydev);
|
if (phydev->irq > 0) |
phy_start_interrupts(phydev);
|
|
return 0; |
}
|
EXPORT_SYMBOL(phy_connect_direct);
|
|
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, <-------+
u32 flags, phy_interface_t
interface)
{
struct device *d = &phydev->dev;
int err;

/* Assume that if there is no driver, that it doesn't
* exist, and we should use the genphy driver.
*/
if (NULL == d->driver) {
if (phydev->is_c45)
d
->driver = &genphy_driver[GENPHY_DRV_10G].driver;
else
d
->driver = &genphy_driver[GENPHY_DRV_1G].driver;

err
= d->driver->probe(d);
if (err >= 0)
err
= device_bind_driver(d);

if (err)
return err;
}

if (phydev->attached_dev) {
dev_err(
&dev->dev, "PHY already attached\n");
return -EBUSY;
}

phydev
->attached_dev = dev;
dev
->phydev = phydev;

phydev
->dev_flags = flags;

phydev
->interface = interface;

phydev
->state = PHY_READY;

/* Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface)
*/
err
= phy_init_hw(phydev); --------------------+
if (err) |
phy_detach(phydev);
|
else |
phy_resume(phydev);
|
|
return err; |
}
|
EXPORT_SYMBOL(phy_attach_direct);
|
|
int phy_init_hw(struct phy_device *phydev) <------------+
{
int ret;

if (!phydev->drv || !phydev->drv->config_init)
return 0;

ret
= phy_write(phydev, MII_BMCR, BMCR_RESET);
if (ret < 0)
return ret;

ret
= phy_poll_reset(phydev);
if (ret < 0)
return ret;

ret
= phy_scan_fixups(phydev); -------------+
if (ret < 0) |
return ret; |
|
return phydev->drv->config_init(phydev); |
}
|
EXPORT_SYMBOL(phy_init_hw);
|
|
/* Runs any matching fixups for this phydev */ |
int phy_scan_fixups(struct phy_device *phydev) <--------+
{
struct phy_fixup *fixup;

mutex_lock(
&phy_fixup_lock);
list_for_each_entry(fixup,
&phy_fixup_list, list) { ------------------+
if (phy_needs_fixup(phydev, fixup)) { --------+ |
int err = fixup->run(phydev); | |
| |
if (err < 0) { | |
mutex_unlock(
&phy_fixup_lock); | |
return err; | |
}
| |
}
| |
}
| |
mutex_unlock(
&phy_fixup_lock); | |
| |
return 0; | |
}
| |
EXPORT_SYMBOL(phy_scan_fixups);
| |
v
--------------------------------------+ |
static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) |
{
|
if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0) |
if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0) |
return 0; |
|
if ((fixup->phy_uid & fixup->phy_uid_mask) != |
(phydev
->phy_id & fixup->phy_uid_mask)) |
if (fixup->phy_uid != PHY_ANY_UID) |
return 0; |
|
return 1; |
}
|
|
static LIST_HEAD(phy_fixup_list); <-----------------+
|
int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, ----*-+
int (*run)(struct phy_device *)) | |
{
| |
struct phy_fixup *fixup = kzalloc(sizeof(*fixup), GFP_KERNEL); | |
| |
if (!fixup) | |
return -ENOMEM; | |
| |
strlcpy(fixup
->bus_id, bus_id, sizeof(fixup->bus_id)); | |
fixup
->phy_uid = phy_uid; | |
fixup
->phy_uid_mask = phy_uid_mask; | |
fixup
->run = run; | |
| |
mutex_lock(
&phy_fixup_lock); | |
list_add_tail(
&fixup->list, &phy_fixup_list); <-----------------+ |
mutex_unlock(
&phy_fixup_lock); |
|
return 0; |
}
|
EXPORT_SYMBOL(phy_register_fixup);
|
|
static void __init imx6q_enet_phy_init(void) -------------------*-+
{
| |
if (IS_BUILTIN(CONFIG_PHYLIB)) { | |
phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
| |
ksz9021rn_phy_fixup);
| |
phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,
| |
ksz9031rn_phy_fixup);
| |
phy_register_fixup_for_uid(PHY_ID_AR8031,
0xffffffff, <-------------+ |
ar8031_phy_fixup);
--------------+ |
phy_register_fixup_for_uid(PHY_ID_AR8035,
0xffffffef, | |
ar8035_phy_fixup);
| |
}
| |
}
| |
| |
static int ar8031_phy_fixup(struct phy_device *dev) <-------------+ |
{
|
u16 val;
|
|
/* Set RGMII IO voltage to 1.8V */ |
phy_write(dev,
0x1d, 0x1f); |
phy_write(dev,
0x1e, 0x8); |
|
/* disable phy AR8031 SmartEEE function. */ |
phy_write(dev,
0xd, 0x3); |
phy_write(dev,
0xe, 0x805d); |
phy_write(dev,
0xd, 0x4003); |
val
= phy_read(dev, 0xe); |
val
&= ~(0x1 << 8); |
phy_write(dev,
0xe, val); |
|
/* To enable AR8031 output a 125MHz clk from CLK_25M */ |
phy_write(dev,
0xd, 0x7); |
phy_write(dev,
0xe, 0x8016); |
phy_write(dev,
0xd, 0x4007); |
|
val
= phy_read(dev, 0xe); |
val
&= 0xffe3; |
val
|= 0x18; |
phy_write(dev,
0xe, val); |
|
/* introduce tx clock delay */ |
phy_write(dev,
0x1d, 0x5); |
val
= phy_read(dev, 0x1e); |
val
|= 0x0100; |
phy_write(dev,
0x1e, val); |
|
return 0; |
}
|
|
static inline void imx6q_enet_init(void) -----------------------------------*-+
{
| |
imx6_enet_mac_init(
"fsl,imx6q-fec"); | |
imx6q_enet_phy_init();
<-----------------------------------+ |
imx6q_1588_init();
|
if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0) |
imx6q_enet_clk_sel();
|
imx6q_enet_plt_init();
|
}
|
|
static void __init imx6q_init_machine(void) |
{
|
struct device *parent; |
|
if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0) |
imx_print_silicon_rev(
"i.MX6QP", IMX_CHIP_REVISION_1_0); |
else |
imx_print_silicon_rev(cpu_is_imx6dl()
? "i.MX6DL" : "i.MX6Q", |
imx_get_soc_revision());
|
|
mxc_arch_reset_init_dt();
|
|
parent
= imx_soc_device_init(); |
if (parent == NULL) |
pr_warn(
"failed to initialize soc device\n"); |
|
of_platform_populate(NULL, of_default_bus_match_table,
|
imx6q_auxdata_lookup, parent);
|
|
imx6q_enet_init();
<---------------------------+
imx_anatop_init();
imx6q_csi_mux_init();
cpu_is_imx6q()
? imx6q_pm_init() : imx6dl_pm_init();
imx6q_mini_pcie_init();
}