/**********************************************************************************
* 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();
}