Path: blob/master/arch/powerpc/sysdev/mv64x60_dev.c
10818 views
/*1* Platform device setup for Marvell mv64360/mv64460 host bridges (Discovery)2*3* Author: Dale Farnsworth <[email protected]>4*5* 2007 (c) MontaVista, Software, Inc. This file is licensed under6* the terms of the GNU General Public License version 2. This program7* is licensed "as is" without any warranty of any kind, whether express8* or implied.9*/1011#include <linux/stddef.h>12#include <linux/kernel.h>13#include <linux/init.h>14#include <linux/console.h>15#include <linux/mv643xx.h>16#include <linux/platform_device.h>17#include <linux/of_platform.h>18#include <linux/of_net.h>19#include <linux/dma-mapping.h>2021#include <asm/prom.h>2223/* These functions provide the necessary setup for the mv64x60 drivers. */2425static struct of_device_id __initdata of_mv64x60_devices[] = {26{ .compatible = "marvell,mv64306-devctrl", },27{}28};2930/*31* Create MPSC platform devices32*/33static int __init mv64x60_mpsc_register_shared_pdev(struct device_node *np)34{35struct platform_device *pdev;36struct resource r[2];37struct mpsc_shared_pdata pdata;38const phandle *ph;39struct device_node *mpscrouting, *mpscintr;40int err;4142ph = of_get_property(np, "mpscrouting", NULL);43mpscrouting = of_find_node_by_phandle(*ph);44if (!mpscrouting)45return -ENODEV;4647err = of_address_to_resource(mpscrouting, 0, &r[0]);48of_node_put(mpscrouting);49if (err)50return err;5152ph = of_get_property(np, "mpscintr", NULL);53mpscintr = of_find_node_by_phandle(*ph);54if (!mpscintr)55return -ENODEV;5657err = of_address_to_resource(mpscintr, 0, &r[1]);58of_node_put(mpscintr);59if (err)60return err;6162memset(&pdata, 0, sizeof(pdata));6364pdev = platform_device_alloc(MPSC_SHARED_NAME, 0);65if (!pdev)66return -ENOMEM;6768err = platform_device_add_resources(pdev, r, 2);69if (err)70goto error;7172err = platform_device_add_data(pdev, &pdata, sizeof(pdata));73if (err)74goto error;7576err = platform_device_add(pdev);77if (err)78goto error;7980return 0;8182error:83platform_device_put(pdev);84return err;85}868788static int __init mv64x60_mpsc_device_setup(struct device_node *np, int id)89{90struct resource r[5];91struct mpsc_pdata pdata;92struct platform_device *pdev;93const unsigned int *prop;94const phandle *ph;95struct device_node *sdma, *brg;96int err;97int port_number;9899/* only register the shared platform device the first time through */100if (id == 0 && (err = mv64x60_mpsc_register_shared_pdev(np)))101return err;102103memset(r, 0, sizeof(r));104105err = of_address_to_resource(np, 0, &r[0]);106if (err)107return err;108109of_irq_to_resource(np, 0, &r[4]);110111ph = of_get_property(np, "sdma", NULL);112sdma = of_find_node_by_phandle(*ph);113if (!sdma)114return -ENODEV;115116of_irq_to_resource(sdma, 0, &r[3]);117err = of_address_to_resource(sdma, 0, &r[1]);118of_node_put(sdma);119if (err)120return err;121122ph = of_get_property(np, "brg", NULL);123brg = of_find_node_by_phandle(*ph);124if (!brg)125return -ENODEV;126127err = of_address_to_resource(brg, 0, &r[2]);128of_node_put(brg);129if (err)130return err;131132prop = of_get_property(np, "cell-index", NULL);133if (!prop)134return -ENODEV;135port_number = *(int *)prop;136137memset(&pdata, 0, sizeof(pdata));138139pdata.cache_mgmt = 1; /* All current revs need this set */140141pdata.max_idle = 40; /* default */142prop = of_get_property(np, "max_idle", NULL);143if (prop)144pdata.max_idle = *prop;145146prop = of_get_property(brg, "current-speed", NULL);147if (prop)148pdata.default_baud = *prop;149150/* Default is 8 bits, no parity, no flow control */151pdata.default_bits = 8;152pdata.default_parity = 'n';153pdata.default_flow = 'n';154155prop = of_get_property(np, "chr_1", NULL);156if (prop)157pdata.chr_1_val = *prop;158159prop = of_get_property(np, "chr_2", NULL);160if (prop)161pdata.chr_2_val = *prop;162163prop = of_get_property(np, "chr_10", NULL);164if (prop)165pdata.chr_10_val = *prop;166167prop = of_get_property(np, "mpcr", NULL);168if (prop)169pdata.mpcr_val = *prop;170171prop = of_get_property(brg, "bcr", NULL);172if (prop)173pdata.bcr_val = *prop;174175pdata.brg_can_tune = 1; /* All current revs need this set */176177prop = of_get_property(brg, "clock-src", NULL);178if (prop)179pdata.brg_clk_src = *prop;180181prop = of_get_property(brg, "clock-frequency", NULL);182if (prop)183pdata.brg_clk_freq = *prop;184185pdev = platform_device_alloc(MPSC_CTLR_NAME, port_number);186if (!pdev)187return -ENOMEM;188pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);189190err = platform_device_add_resources(pdev, r, 5);191if (err)192goto error;193194err = platform_device_add_data(pdev, &pdata, sizeof(pdata));195if (err)196goto error;197198err = platform_device_add(pdev);199if (err)200goto error;201202return 0;203204error:205platform_device_put(pdev);206return err;207}208209/*210* Create mv64x60_eth platform devices211*/212static struct platform_device * __init mv64x60_eth_register_shared_pdev(213struct device_node *np, int id)214{215struct platform_device *pdev;216struct resource r[1];217int err;218219err = of_address_to_resource(np, 0, &r[0]);220if (err)221return ERR_PTR(err);222223pdev = platform_device_register_simple(MV643XX_ETH_SHARED_NAME, id,224r, 1);225return pdev;226}227228static int __init mv64x60_eth_device_setup(struct device_node *np, int id,229struct platform_device *shared_pdev)230{231struct resource r[1];232struct mv643xx_eth_platform_data pdata;233struct platform_device *pdev;234struct device_node *phy;235const u8 *mac_addr;236const int *prop;237const phandle *ph;238int err;239240memset(r, 0, sizeof(r));241of_irq_to_resource(np, 0, &r[0]);242243memset(&pdata, 0, sizeof(pdata));244245pdata.shared = shared_pdev;246247prop = of_get_property(np, "reg", NULL);248if (!prop)249return -ENODEV;250pdata.port_number = *prop;251252mac_addr = of_get_mac_address(np);253if (mac_addr)254memcpy(pdata.mac_addr, mac_addr, 6);255256prop = of_get_property(np, "speed", NULL);257if (prop)258pdata.speed = *prop;259260prop = of_get_property(np, "tx_queue_size", NULL);261if (prop)262pdata.tx_queue_size = *prop;263264prop = of_get_property(np, "rx_queue_size", NULL);265if (prop)266pdata.rx_queue_size = *prop;267268prop = of_get_property(np, "tx_sram_addr", NULL);269if (prop)270pdata.tx_sram_addr = *prop;271272prop = of_get_property(np, "tx_sram_size", NULL);273if (prop)274pdata.tx_sram_size = *prop;275276prop = of_get_property(np, "rx_sram_addr", NULL);277if (prop)278pdata.rx_sram_addr = *prop;279280prop = of_get_property(np, "rx_sram_size", NULL);281if (prop)282pdata.rx_sram_size = *prop;283284ph = of_get_property(np, "phy", NULL);285if (!ph)286return -ENODEV;287288phy = of_find_node_by_phandle(*ph);289if (phy == NULL)290return -ENODEV;291292prop = of_get_property(phy, "reg", NULL);293if (prop)294pdata.phy_addr = MV643XX_ETH_PHY_ADDR(*prop);295296of_node_put(phy);297298pdev = platform_device_alloc(MV643XX_ETH_NAME, id);299if (!pdev)300return -ENOMEM;301302pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);303err = platform_device_add_resources(pdev, r, 1);304if (err)305goto error;306307err = platform_device_add_data(pdev, &pdata, sizeof(pdata));308if (err)309goto error;310311err = platform_device_add(pdev);312if (err)313goto error;314315return 0;316317error:318platform_device_put(pdev);319return err;320}321322/*323* Create mv64x60_i2c platform devices324*/325static int __init mv64x60_i2c_device_setup(struct device_node *np, int id)326{327struct resource r[2];328struct platform_device *pdev;329struct mv64xxx_i2c_pdata pdata;330const unsigned int *prop;331int err;332333memset(r, 0, sizeof(r));334335err = of_address_to_resource(np, 0, &r[0]);336if (err)337return err;338339of_irq_to_resource(np, 0, &r[1]);340341memset(&pdata, 0, sizeof(pdata));342343pdata.freq_m = 8; /* default */344prop = of_get_property(np, "freq_m", NULL);345if (prop)346pdata.freq_m = *prop;347348pdata.freq_n = 3; /* default */349prop = of_get_property(np, "freq_n", NULL);350if (prop)351pdata.freq_n = *prop;352353pdata.timeout = 1000; /* default: 1 second */354355pdev = platform_device_alloc(MV64XXX_I2C_CTLR_NAME, id);356if (!pdev)357return -ENOMEM;358359err = platform_device_add_resources(pdev, r, 2);360if (err)361goto error;362363err = platform_device_add_data(pdev, &pdata, sizeof(pdata));364if (err)365goto error;366367err = platform_device_add(pdev);368if (err)369goto error;370371return 0;372373error:374platform_device_put(pdev);375return err;376}377378/*379* Create mv64x60_wdt platform devices380*/381static int __init mv64x60_wdt_device_setup(struct device_node *np, int id)382{383struct resource r;384struct platform_device *pdev;385struct mv64x60_wdt_pdata pdata;386const unsigned int *prop;387int err;388389err = of_address_to_resource(np, 0, &r);390if (err)391return err;392393memset(&pdata, 0, sizeof(pdata));394395pdata.timeout = 10; /* Default: 10 seconds */396397np = of_get_parent(np);398if (!np)399return -ENODEV;400401prop = of_get_property(np, "clock-frequency", NULL);402of_node_put(np);403if (!prop)404return -ENODEV;405pdata.bus_clk = *prop / 1000000; /* wdt driver wants freq in MHz */406407pdev = platform_device_alloc(MV64x60_WDT_NAME, id);408if (!pdev)409return -ENOMEM;410411err = platform_device_add_resources(pdev, &r, 1);412if (err)413goto error;414415err = platform_device_add_data(pdev, &pdata, sizeof(pdata));416if (err)417goto error;418419err = platform_device_add(pdev);420if (err)421goto error;422423return 0;424425error:426platform_device_put(pdev);427return err;428}429430static int __init mv64x60_device_setup(void)431{432struct device_node *np, *np2;433struct platform_device *pdev;434int id, id2;435int err;436437id = 0;438for_each_compatible_node(np, "serial", "marvell,mv64360-mpsc") {439err = mv64x60_mpsc_device_setup(np, id++);440if (err)441printk(KERN_ERR "Failed to initialize MV64x60 "442"serial device %s: error %d.\n",443np->full_name, err);444}445446id = 0;447id2 = 0;448for_each_compatible_node(np, NULL, "marvell,mv64360-eth-group") {449pdev = mv64x60_eth_register_shared_pdev(np, id++);450if (IS_ERR(pdev)) {451err = PTR_ERR(pdev);452printk(KERN_ERR "Failed to initialize MV64x60 "453"network block %s: error %d.\n",454np->full_name, err);455continue;456}457for_each_child_of_node(np, np2) {458if (!of_device_is_compatible(np2,459"marvell,mv64360-eth"))460continue;461err = mv64x60_eth_device_setup(np2, id2++, pdev);462if (err)463printk(KERN_ERR "Failed to initialize "464"MV64x60 network device %s: "465"error %d.\n",466np2->full_name, err);467}468}469470id = 0;471for_each_compatible_node(np, "i2c", "marvell,mv64360-i2c") {472err = mv64x60_i2c_device_setup(np, id++);473if (err)474printk(KERN_ERR "Failed to initialize MV64x60 I2C "475"bus %s: error %d.\n",476np->full_name, err);477}478479/* support up to one watchdog timer */480np = of_find_compatible_node(np, NULL, "marvell,mv64360-wdt");481if (np) {482if ((err = mv64x60_wdt_device_setup(np, id)))483printk(KERN_ERR "Failed to initialize MV64x60 "484"Watchdog %s: error %d.\n",485np->full_name, err);486of_node_put(np);487}488489/* Now add every node that is on the device bus */490for_each_compatible_node(np, NULL, "marvell,mv64360")491of_platform_bus_probe(np, of_mv64x60_devices, NULL);492493return 0;494}495arch_initcall(mv64x60_device_setup);496497static int __init mv64x60_add_mpsc_console(void)498{499struct device_node *np = NULL;500const char *prop;501502prop = of_get_property(of_chosen, "linux,stdout-path", NULL);503if (prop == NULL)504goto not_mpsc;505506np = of_find_node_by_path(prop);507if (!np)508goto not_mpsc;509510if (!of_device_is_compatible(np, "marvell,mv64360-mpsc"))511goto not_mpsc;512513prop = of_get_property(np, "cell-index", NULL);514if (!prop)515goto not_mpsc;516517add_preferred_console("ttyMM", *(int *)prop, NULL);518519not_mpsc:520return 0;521}522console_initcall(mv64x60_add_mpsc_console);523524525