113be5432SRobert Tivy /* 213be5432SRobert Tivy * Remote processor machine-specific module for DA8XX 313be5432SRobert Tivy * 413be5432SRobert Tivy * Copyright (C) 2013 Texas Instruments, Inc. 513be5432SRobert Tivy * 613be5432SRobert Tivy * This program is free software; you can redistribute it and/or 713be5432SRobert Tivy * modify it under the terms of the GNU General Public License 813be5432SRobert Tivy * version 2 as published by the Free Software Foundation. 913be5432SRobert Tivy */ 1013be5432SRobert Tivy 1113be5432SRobert Tivy #include <linux/bitops.h> 1213be5432SRobert Tivy #include <linux/clk.h> 13b2201ee5SBartosz Golaszewski #include <linux/reset.h> 1413be5432SRobert Tivy #include <linux/err.h> 1513be5432SRobert Tivy #include <linux/interrupt.h> 1613be5432SRobert Tivy #include <linux/io.h> 1713be5432SRobert Tivy #include <linux/irq.h> 1813be5432SRobert Tivy #include <linux/kernel.h> 1913be5432SRobert Tivy #include <linux/module.h> 2061696580SSuman Anna #include <linux/of_reserved_mem.h> 2113be5432SRobert Tivy #include <linux/platform_device.h> 2213be5432SRobert Tivy #include <linux/remoteproc.h> 2313be5432SRobert Tivy 2413be5432SRobert Tivy #include "remoteproc_internal.h" 2513be5432SRobert Tivy 2613be5432SRobert Tivy static char *da8xx_fw_name; 2724ff1417SBartosz Golaszewski module_param(da8xx_fw_name, charp, 0444); 2813be5432SRobert Tivy MODULE_PARM_DESC(da8xx_fw_name, 29e17aee37SSuman Anna "Name of DSP firmware file in /lib/firmware (if not specified defaults to 'rproc-dsp-fw')"); 3013be5432SRobert Tivy 3113be5432SRobert Tivy /* 3213be5432SRobert Tivy * OMAP-L138 Technical References: 3313be5432SRobert Tivy * http://www.ti.com/product/omap-l138 3413be5432SRobert Tivy */ 3513be5432SRobert Tivy #define SYSCFG_CHIPSIG0 BIT(0) 3613be5432SRobert Tivy #define SYSCFG_CHIPSIG1 BIT(1) 3713be5432SRobert Tivy #define SYSCFG_CHIPSIG2 BIT(2) 3813be5432SRobert Tivy #define SYSCFG_CHIPSIG3 BIT(3) 3913be5432SRobert Tivy #define SYSCFG_CHIPSIG4 BIT(4) 4013be5432SRobert Tivy 4159b2355fSSuman Anna #define DA8XX_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1) 4259b2355fSSuman Anna 4359b2355fSSuman Anna /** 4459b2355fSSuman Anna * struct da8xx_rproc_mem - internal memory structure 4559b2355fSSuman Anna * @cpu_addr: MPU virtual address of the memory region 4659b2355fSSuman Anna * @bus_addr: Bus address used to access the memory region 4759b2355fSSuman Anna * @dev_addr: Device address of the memory region from DSP view 4859b2355fSSuman Anna * @size: Size of the memory region 4959b2355fSSuman Anna */ 5059b2355fSSuman Anna struct da8xx_rproc_mem { 5159b2355fSSuman Anna void __iomem *cpu_addr; 5259b2355fSSuman Anna phys_addr_t bus_addr; 5359b2355fSSuman Anna u32 dev_addr; 5459b2355fSSuman Anna size_t size; 5559b2355fSSuman Anna }; 5659b2355fSSuman Anna 5713be5432SRobert Tivy /** 5813be5432SRobert Tivy * struct da8xx_rproc - da8xx remote processor instance state 5913be5432SRobert Tivy * @rproc: rproc handle 6059b2355fSSuman Anna * @mem: internal memory regions data 6159b2355fSSuman Anna * @num_mems: number of internal memory regions 6213be5432SRobert Tivy * @dsp_clk: placeholder for platform's DSP clk 6313be5432SRobert Tivy * @ack_fxn: chip-specific ack function for ack'ing irq 6413be5432SRobert Tivy * @irq_data: ack_fxn function parameter 6513be5432SRobert Tivy * @chipsig: virt ptr to DSP interrupt registers (CHIPSIG & CHIPSIG_CLR) 6613be5432SRobert Tivy * @bootreg: virt ptr to DSP boot address register (HOST1CFG) 6713be5432SRobert Tivy * @irq: irq # used by this instance 6813be5432SRobert Tivy */ 6913be5432SRobert Tivy struct da8xx_rproc { 7013be5432SRobert Tivy struct rproc *rproc; 7159b2355fSSuman Anna struct da8xx_rproc_mem *mem; 7259b2355fSSuman Anna int num_mems; 7313be5432SRobert Tivy struct clk *dsp_clk; 74b2201ee5SBartosz Golaszewski struct reset_control *dsp_reset; 7513be5432SRobert Tivy void (*ack_fxn)(struct irq_data *data); 7613be5432SRobert Tivy struct irq_data *irq_data; 7713be5432SRobert Tivy void __iomem *chipsig; 7813be5432SRobert Tivy void __iomem *bootreg; 7913be5432SRobert Tivy int irq; 8013be5432SRobert Tivy }; 8113be5432SRobert Tivy 8213be5432SRobert Tivy /** 8313be5432SRobert Tivy * handle_event() - inbound virtqueue message workqueue function 8413be5432SRobert Tivy * 8513be5432SRobert Tivy * This function is registered as a kernel thread and is scheduled by the 8613be5432SRobert Tivy * kernel handler. 8713be5432SRobert Tivy */ 8813be5432SRobert Tivy static irqreturn_t handle_event(int irq, void *p) 8913be5432SRobert Tivy { 9013be5432SRobert Tivy struct rproc *rproc = (struct rproc *)p; 9113be5432SRobert Tivy 9213be5432SRobert Tivy /* Process incoming buffers on all our vrings */ 9313be5432SRobert Tivy rproc_vq_interrupt(rproc, 0); 9413be5432SRobert Tivy rproc_vq_interrupt(rproc, 1); 9513be5432SRobert Tivy 9613be5432SRobert Tivy return IRQ_HANDLED; 9713be5432SRobert Tivy } 9813be5432SRobert Tivy 9913be5432SRobert Tivy /** 10013be5432SRobert Tivy * da8xx_rproc_callback() - inbound virtqueue message handler 10113be5432SRobert Tivy * 10213be5432SRobert Tivy * This handler is invoked directly by the kernel whenever the remote 10313be5432SRobert Tivy * core (DSP) has modified the state of a virtqueue. There is no 10413be5432SRobert Tivy * "payload" message indicating the virtqueue index as is the case with 10513be5432SRobert Tivy * mailbox-based implementations on OMAP4. As such, this handler "polls" 10613be5432SRobert Tivy * each known virtqueue index for every invocation. 10713be5432SRobert Tivy */ 10813be5432SRobert Tivy static irqreturn_t da8xx_rproc_callback(int irq, void *p) 10913be5432SRobert Tivy { 11013be5432SRobert Tivy struct rproc *rproc = (struct rproc *)p; 11113be5432SRobert Tivy struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; 11213be5432SRobert Tivy u32 chipsig; 11313be5432SRobert Tivy 11413be5432SRobert Tivy chipsig = readl(drproc->chipsig); 11513be5432SRobert Tivy if (chipsig & SYSCFG_CHIPSIG0) { 11613be5432SRobert Tivy /* Clear interrupt level source */ 11713be5432SRobert Tivy writel(SYSCFG_CHIPSIG0, drproc->chipsig + 4); 11813be5432SRobert Tivy 11913be5432SRobert Tivy /* 12013be5432SRobert Tivy * ACK intr to AINTC. 12113be5432SRobert Tivy * 12213be5432SRobert Tivy * It has already been ack'ed by the kernel before calling 12313be5432SRobert Tivy * this function, but since the ARM<->DSP interrupts in the 12413be5432SRobert Tivy * CHIPSIG register are "level" instead of "pulse" variety, 12513be5432SRobert Tivy * we need to ack it after taking down the level else we'll 12613be5432SRobert Tivy * be called again immediately after returning. 12713be5432SRobert Tivy */ 12813be5432SRobert Tivy drproc->ack_fxn(drproc->irq_data); 12913be5432SRobert Tivy 13013be5432SRobert Tivy return IRQ_WAKE_THREAD; 13113be5432SRobert Tivy } 13213be5432SRobert Tivy 13313be5432SRobert Tivy return IRQ_HANDLED; 13413be5432SRobert Tivy } 13513be5432SRobert Tivy 13613be5432SRobert Tivy static int da8xx_rproc_start(struct rproc *rproc) 13713be5432SRobert Tivy { 13813be5432SRobert Tivy struct device *dev = rproc->dev.parent; 13913be5432SRobert Tivy struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; 14013be5432SRobert Tivy struct clk *dsp_clk = drproc->dsp_clk; 141b2201ee5SBartosz Golaszewski struct reset_control *dsp_reset = drproc->dsp_reset; 1422310eae9SBartosz Golaszewski int ret; 14313be5432SRobert Tivy 14413be5432SRobert Tivy /* hw requires the start (boot) address be on 1KB boundary */ 14513be5432SRobert Tivy if (rproc->bootaddr & 0x3ff) { 14613be5432SRobert Tivy dev_err(dev, "invalid boot address: must be aligned to 1KB\n"); 14713be5432SRobert Tivy 14813be5432SRobert Tivy return -EINVAL; 14913be5432SRobert Tivy } 15013be5432SRobert Tivy 15113be5432SRobert Tivy writel(rproc->bootaddr, drproc->bootreg); 15213be5432SRobert Tivy 1535d26f068SBartosz Golaszewski ret = clk_prepare_enable(dsp_clk); 1542310eae9SBartosz Golaszewski if (ret) { 1555d26f068SBartosz Golaszewski dev_err(dev, "clk_prepare_enable() failed: %d\n", ret); 1562310eae9SBartosz Golaszewski return ret; 1572310eae9SBartosz Golaszewski } 1582310eae9SBartosz Golaszewski 159b2201ee5SBartosz Golaszewski ret = reset_control_deassert(dsp_reset); 160b2201ee5SBartosz Golaszewski if (ret) { 161b2201ee5SBartosz Golaszewski dev_err(dev, "reset_control_deassert() failed: %d\n", ret); 162b2201ee5SBartosz Golaszewski clk_disable_unprepare(dsp_clk); 163b2201ee5SBartosz Golaszewski return ret; 164b2201ee5SBartosz Golaszewski } 16513be5432SRobert Tivy 16613be5432SRobert Tivy return 0; 16713be5432SRobert Tivy } 16813be5432SRobert Tivy 16913be5432SRobert Tivy static int da8xx_rproc_stop(struct rproc *rproc) 17013be5432SRobert Tivy { 17113be5432SRobert Tivy struct da8xx_rproc *drproc = rproc->priv; 172b2201ee5SBartosz Golaszewski struct device *dev = rproc->dev.parent; 173b2201ee5SBartosz Golaszewski int ret; 17413be5432SRobert Tivy 175b2201ee5SBartosz Golaszewski ret = reset_control_assert(drproc->dsp_reset); 176b2201ee5SBartosz Golaszewski if (ret) { 177b2201ee5SBartosz Golaszewski dev_err(dev, "reset_control_assert() failed: %d\n", ret); 178b2201ee5SBartosz Golaszewski return ret; 179b2201ee5SBartosz Golaszewski } 180b2201ee5SBartosz Golaszewski 1815d26f068SBartosz Golaszewski clk_disable_unprepare(drproc->dsp_clk); 18213be5432SRobert Tivy 18313be5432SRobert Tivy return 0; 18413be5432SRobert Tivy } 18513be5432SRobert Tivy 18613be5432SRobert Tivy /* kick a virtqueue */ 18713be5432SRobert Tivy static void da8xx_rproc_kick(struct rproc *rproc, int vqid) 18813be5432SRobert Tivy { 18913be5432SRobert Tivy struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; 19013be5432SRobert Tivy 19156324d7aSAnna, Suman /* Interrupt remote proc */ 19213be5432SRobert Tivy writel(SYSCFG_CHIPSIG2, drproc->chipsig); 19313be5432SRobert Tivy } 19413be5432SRobert Tivy 195c008fad2SBhumika Goyal static const struct rproc_ops da8xx_rproc_ops = { 19613be5432SRobert Tivy .start = da8xx_rproc_start, 19713be5432SRobert Tivy .stop = da8xx_rproc_stop, 19813be5432SRobert Tivy .kick = da8xx_rproc_kick, 19913be5432SRobert Tivy }; 20013be5432SRobert Tivy 20159b2355fSSuman Anna static int da8xx_rproc_get_internal_memories(struct platform_device *pdev, 20259b2355fSSuman Anna struct da8xx_rproc *drproc) 20359b2355fSSuman Anna { 20459b2355fSSuman Anna static const char * const mem_names[] = {"l2sram", "l1pram", "l1dram"}; 20559b2355fSSuman Anna int num_mems = ARRAY_SIZE(mem_names); 20659b2355fSSuman Anna struct device *dev = &pdev->dev; 20759b2355fSSuman Anna struct resource *res; 20859b2355fSSuman Anna int i; 20959b2355fSSuman Anna 21059b2355fSSuman Anna drproc->mem = devm_kcalloc(dev, num_mems, sizeof(*drproc->mem), 21159b2355fSSuman Anna GFP_KERNEL); 21259b2355fSSuman Anna if (!drproc->mem) 21359b2355fSSuman Anna return -ENOMEM; 21459b2355fSSuman Anna 21559b2355fSSuman Anna for (i = 0; i < num_mems; i++) { 21659b2355fSSuman Anna res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 21759b2355fSSuman Anna mem_names[i]); 21859b2355fSSuman Anna drproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res); 21959b2355fSSuman Anna if (IS_ERR(drproc->mem[i].cpu_addr)) { 22059b2355fSSuman Anna dev_err(dev, "failed to parse and map %s memory\n", 22159b2355fSSuman Anna mem_names[i]); 22259b2355fSSuman Anna return PTR_ERR(drproc->mem[i].cpu_addr); 22359b2355fSSuman Anna } 22459b2355fSSuman Anna drproc->mem[i].bus_addr = res->start; 22559b2355fSSuman Anna drproc->mem[i].dev_addr = 22659b2355fSSuman Anna res->start & DA8XX_RPROC_LOCAL_ADDRESS_MASK; 22759b2355fSSuman Anna drproc->mem[i].size = resource_size(res); 22859b2355fSSuman Anna 22959b2355fSSuman Anna dev_dbg(dev, "memory %8s: bus addr %pa size 0x%x va %p da 0x%x\n", 23059b2355fSSuman Anna mem_names[i], &drproc->mem[i].bus_addr, 23159b2355fSSuman Anna drproc->mem[i].size, drproc->mem[i].cpu_addr, 23259b2355fSSuman Anna drproc->mem[i].dev_addr); 23359b2355fSSuman Anna } 23459b2355fSSuman Anna drproc->num_mems = num_mems; 23559b2355fSSuman Anna 23659b2355fSSuman Anna return 0; 23759b2355fSSuman Anna } 23859b2355fSSuman Anna 23913be5432SRobert Tivy static int da8xx_rproc_probe(struct platform_device *pdev) 24013be5432SRobert Tivy { 24113be5432SRobert Tivy struct device *dev = &pdev->dev; 24213be5432SRobert Tivy struct da8xx_rproc *drproc; 24313be5432SRobert Tivy struct rproc *rproc; 24413be5432SRobert Tivy struct irq_data *irq_data; 24513be5432SRobert Tivy struct resource *bootreg_res; 24613be5432SRobert Tivy struct resource *chipsig_res; 24713be5432SRobert Tivy struct clk *dsp_clk; 248b2201ee5SBartosz Golaszewski struct reset_control *dsp_reset; 24913be5432SRobert Tivy void __iomem *chipsig; 25013be5432SRobert Tivy void __iomem *bootreg; 25113be5432SRobert Tivy int irq; 25213be5432SRobert Tivy int ret; 25313be5432SRobert Tivy 25413be5432SRobert Tivy irq = platform_get_irq(pdev, 0); 25513be5432SRobert Tivy if (irq < 0) { 25613be5432SRobert Tivy dev_err(dev, "platform_get_irq(pdev, 0) error: %d\n", irq); 25713be5432SRobert Tivy return irq; 25813be5432SRobert Tivy } 25913be5432SRobert Tivy 26013be5432SRobert Tivy irq_data = irq_get_irq_data(irq); 26113be5432SRobert Tivy if (!irq_data) { 26213be5432SRobert Tivy dev_err(dev, "irq_get_irq_data(%d): NULL\n", irq); 26313be5432SRobert Tivy return -EINVAL; 26413be5432SRobert Tivy } 26513be5432SRobert Tivy 2666fb9a8f5SSuman Anna bootreg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 2676fb9a8f5SSuman Anna "host1cfg"); 26813be5432SRobert Tivy bootreg = devm_ioremap_resource(dev, bootreg_res); 26913be5432SRobert Tivy if (IS_ERR(bootreg)) 27013be5432SRobert Tivy return PTR_ERR(bootreg); 27113be5432SRobert Tivy 2726fb9a8f5SSuman Anna chipsig_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 2736fb9a8f5SSuman Anna "chipsig"); 27413be5432SRobert Tivy chipsig = devm_ioremap_resource(dev, chipsig_res); 27513be5432SRobert Tivy if (IS_ERR(chipsig)) 27613be5432SRobert Tivy return PTR_ERR(chipsig); 27713be5432SRobert Tivy 27813be5432SRobert Tivy dsp_clk = devm_clk_get(dev, NULL); 27913be5432SRobert Tivy if (IS_ERR(dsp_clk)) { 28013be5432SRobert Tivy dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk)); 28113be5432SRobert Tivy 28213be5432SRobert Tivy return PTR_ERR(dsp_clk); 28313be5432SRobert Tivy } 28413be5432SRobert Tivy 285b2201ee5SBartosz Golaszewski dsp_reset = devm_reset_control_get_exclusive(dev, NULL); 286b2201ee5SBartosz Golaszewski if (IS_ERR(dsp_reset)) { 287b2201ee5SBartosz Golaszewski if (PTR_ERR(dsp_reset) != -EPROBE_DEFER) 288b2201ee5SBartosz Golaszewski dev_err(dev, "unable to get reset control: %ld\n", 289b2201ee5SBartosz Golaszewski PTR_ERR(dsp_reset)); 290b2201ee5SBartosz Golaszewski 291b2201ee5SBartosz Golaszewski return PTR_ERR(dsp_reset); 292b2201ee5SBartosz Golaszewski } 293b2201ee5SBartosz Golaszewski 29461696580SSuman Anna if (dev->of_node) { 29561696580SSuman Anna ret = of_reserved_mem_device_init(dev); 29661696580SSuman Anna if (ret) { 29761696580SSuman Anna dev_err(dev, "device does not have specific CMA pool: %d\n", 29861696580SSuman Anna ret); 29961696580SSuman Anna return ret; 30061696580SSuman Anna } 30161696580SSuman Anna } 30261696580SSuman Anna 30313be5432SRobert Tivy rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, 30413be5432SRobert Tivy sizeof(*drproc)); 30561696580SSuman Anna if (!rproc) { 30661696580SSuman Anna ret = -ENOMEM; 30761696580SSuman Anna goto free_mem; 30861696580SSuman Anna } 30913be5432SRobert Tivy 310491278b6SSuman Anna /* error recovery is not supported at present */ 311491278b6SSuman Anna rproc->recovery_disabled = true; 312491278b6SSuman Anna 31313be5432SRobert Tivy drproc = rproc->priv; 31413be5432SRobert Tivy drproc->rproc = rproc; 315470ac62fSSuman Anna drproc->dsp_clk = dsp_clk; 316b2201ee5SBartosz Golaszewski drproc->dsp_reset = dsp_reset; 317315491e5SSuman Anna rproc->has_iommu = false; 31813be5432SRobert Tivy 31959b2355fSSuman Anna ret = da8xx_rproc_get_internal_memories(pdev, drproc); 32059b2355fSSuman Anna if (ret) 32159b2355fSSuman Anna goto free_rproc; 32259b2355fSSuman Anna 32313be5432SRobert Tivy platform_set_drvdata(pdev, rproc); 32413be5432SRobert Tivy 32513be5432SRobert Tivy /* everything the ISR needs is now setup, so hook it up */ 32613be5432SRobert Tivy ret = devm_request_threaded_irq(dev, irq, da8xx_rproc_callback, 32713be5432SRobert Tivy handle_event, 0, "da8xx-remoteproc", 32813be5432SRobert Tivy rproc); 32913be5432SRobert Tivy if (ret) { 33013be5432SRobert Tivy dev_err(dev, "devm_request_threaded_irq error: %d\n", ret); 33113be5432SRobert Tivy goto free_rproc; 33213be5432SRobert Tivy } 33313be5432SRobert Tivy 33413be5432SRobert Tivy /* 33513be5432SRobert Tivy * rproc_add() can end up enabling the DSP's clk with the DSP 33613be5432SRobert Tivy * *not* in reset, but da8xx_rproc_start() needs the DSP to be 33713be5432SRobert Tivy * held in reset at the time it is called. 33813be5432SRobert Tivy */ 339b2201ee5SBartosz Golaszewski ret = reset_control_assert(dsp_reset); 34013be5432SRobert Tivy if (ret) 34113be5432SRobert Tivy goto free_rproc; 34213be5432SRobert Tivy 34313be5432SRobert Tivy drproc->chipsig = chipsig; 34413be5432SRobert Tivy drproc->bootreg = bootreg; 34513be5432SRobert Tivy drproc->ack_fxn = irq_data->chip->irq_ack; 34613be5432SRobert Tivy drproc->irq_data = irq_data; 34713be5432SRobert Tivy drproc->irq = irq; 34813be5432SRobert Tivy 34913be5432SRobert Tivy ret = rproc_add(rproc); 35013be5432SRobert Tivy if (ret) { 35113be5432SRobert Tivy dev_err(dev, "rproc_add failed: %d\n", ret); 35213be5432SRobert Tivy goto free_rproc; 35313be5432SRobert Tivy } 35413be5432SRobert Tivy 35513be5432SRobert Tivy return 0; 35613be5432SRobert Tivy 35713be5432SRobert Tivy free_rproc: 358433c0e04SBjorn Andersson rproc_free(rproc); 35961696580SSuman Anna free_mem: 36061696580SSuman Anna if (dev->of_node) 36161696580SSuman Anna of_reserved_mem_device_release(dev); 36213be5432SRobert Tivy return ret; 36313be5432SRobert Tivy } 36413be5432SRobert Tivy 36513be5432SRobert Tivy static int da8xx_rproc_remove(struct platform_device *pdev) 36613be5432SRobert Tivy { 36713be5432SRobert Tivy struct rproc *rproc = platform_get_drvdata(pdev); 36813be5432SRobert Tivy struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; 36961696580SSuman Anna struct device *dev = &pdev->dev; 37013be5432SRobert Tivy 37113be5432SRobert Tivy /* 37213be5432SRobert Tivy * The devm subsystem might end up releasing things before 37313be5432SRobert Tivy * freeing the irq, thus allowing an interrupt to sneak in while 37413be5432SRobert Tivy * the device is being removed. This should prevent that. 37513be5432SRobert Tivy */ 37613be5432SRobert Tivy disable_irq(drproc->irq); 37713be5432SRobert Tivy 37813be5432SRobert Tivy rproc_del(rproc); 379433c0e04SBjorn Andersson rproc_free(rproc); 38061696580SSuman Anna if (dev->of_node) 38161696580SSuman Anna of_reserved_mem_device_release(dev); 38213be5432SRobert Tivy 38313be5432SRobert Tivy return 0; 38413be5432SRobert Tivy } 38513be5432SRobert Tivy 38661696580SSuman Anna static const struct of_device_id davinci_rproc_of_match[] __maybe_unused = { 38761696580SSuman Anna { .compatible = "ti,da850-dsp", }, 38861696580SSuman Anna { /* sentinel */ }, 38961696580SSuman Anna }; 39061696580SSuman Anna MODULE_DEVICE_TABLE(of, davinci_rproc_of_match); 39161696580SSuman Anna 39213be5432SRobert Tivy static struct platform_driver da8xx_rproc_driver = { 39313be5432SRobert Tivy .probe = da8xx_rproc_probe, 39413be5432SRobert Tivy .remove = da8xx_rproc_remove, 39513be5432SRobert Tivy .driver = { 39613be5432SRobert Tivy .name = "davinci-rproc", 39761696580SSuman Anna .of_match_table = of_match_ptr(davinci_rproc_of_match), 39813be5432SRobert Tivy }, 39913be5432SRobert Tivy }; 40013be5432SRobert Tivy 40113be5432SRobert Tivy module_platform_driver(da8xx_rproc_driver); 40213be5432SRobert Tivy 40313be5432SRobert Tivy MODULE_LICENSE("GPL v2"); 40413be5432SRobert Tivy MODULE_DESCRIPTION("DA8XX Remote Processor control driver"); 405