From f052f3aa3ceb62d58224fd7d66328c9d5f9e9226 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Mon, 9 Oct 2023 18:34:07 +0800 Subject: [PATCH] Update to Phytium embeded Kernel v1.1 add homo-rproc driver. Signed-off-by: liutianyu1250 --- .../bindings/remoteproc/homo-rproc.txt | 39 ++ .../boot/dts/phytium/e2000q-demo-board.dts | 1 - .../boot/dts/phytium/e2000q-miniitx-board.dts | 3 + arch/arm64/configs/phytium_defconfig | 5 +- drivers/net/can/phytium/phytium_can.c | 84 +++-- drivers/net/can/phytium/phytium_can.h | 14 +- .../net/can/phytium/phytium_can_platform.c | 3 - drivers/remoteproc/Kconfig | 6 + drivers/remoteproc/Makefile | 1 + drivers/remoteproc/homo_remoteproc.c | 349 ++++++++++++++++++ drivers/spi/spi-phytium-pci.c | 6 +- include/linux/cpuhotplug.h | 1 + sound/pci/hda/hda_phytium.c | 6 +- 13 files changed, 466 insertions(+), 52 deletions(-) create mode 100644 Documentation/devicetree/bindings/remoteproc/homo-rproc.txt create mode 100644 drivers/remoteproc/homo_remoteproc.c diff --git a/Documentation/devicetree/bindings/remoteproc/homo-rproc.txt b/Documentation/devicetree/bindings/remoteproc/homo-rproc.txt new file mode 100644 index 0000000000..00f4c4402e --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/homo-rproc.txt @@ -0,0 +1,39 @@ +homogeneous remoteproc driver +========================================== + +This driver implements communication between remote processors under a homogeneous CPU architecture(SMP). + +Homogeneous RemoteProc Device Node: +================================= +A homo_remoteproc device node is used to represent the remote core instance within SoC. + +Required properties: +-------------------- + - compatible : should be "homo,rproc" + - remote-processor: remote processor's linux cpu logical number + - inter-processor-interrupt: IPI/SGI interrupt number, default is 9 + - memory-region: reserved memory which will be used by remote processor + - firmware-name: the name of openamp image, default is "openamp_core0.elf" + +Example: +-------- + + reserved-memory { + #address-cells = <0x2>; + #size-cells = <0x2>; + ranges; + + rproc: rproc@b0100000 { + no-map; + reg = <0x0 0xb0100000 0x0 0x19900000>; + }; + }; + + homo_rproc: homo_rproc@0 { + compatible = "homo,rproc"; + remote-processor = <3>; + inter-processor-interrupt = <9>; + memory-region = <&rproc>; + firmware-name = "openamp_core0.elf"; + status = "disabled"; + }; diff --git a/arch/arm64/boot/dts/phytium/e2000q-demo-board.dts b/arch/arm64/boot/dts/phytium/e2000q-demo-board.dts index 6ff075e32f..bee198e667 100644 --- a/arch/arm64/boot/dts/phytium/e2000q-demo-board.dts +++ b/arch/arm64/boot/dts/phytium/e2000q-demo-board.dts @@ -244,4 +244,3 @@ &pmdk_dp { &rng0 { status = "okay"; }; - diff --git a/arch/arm64/boot/dts/phytium/e2000q-miniitx-board.dts b/arch/arm64/boot/dts/phytium/e2000q-miniitx-board.dts index 62111978f6..6829a30793 100644 --- a/arch/arm64/boot/dts/phytium/e2000q-miniitx-board.dts +++ b/arch/arm64/boot/dts/phytium/e2000q-miniitx-board.dts @@ -14,6 +14,7 @@ /dts-v1/; /memreserve/ 0x80000000 0x10000; +/memreserve/ 0xf4000000 0x4000000; #include "pe2204.dtsi" @@ -218,6 +219,8 @@ &macb2 { }; &dc0 { + reg = <0x0 0x32000000 0x0 0x8000>, + <0x0 0xf4000000 0x0 0x4000000>; // (optional) pipe_mask = [03]; edp_mask = [00]; status = "okay"; diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index 85a3f657ef..71e7661152 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -1,4 +1,4 @@ -CONFIG_LOCALVERSION="-phytium-embeded-2023-v1.0-GA" +CONFIG_LOCALVERSION="-phytium-embeded-v1.1" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -633,6 +633,9 @@ CONFIG_PHYTIUM_MBOX=y CONFIG_ARM_SMMU=y CONFIG_ARM_SMMU_V3=y CONFIG_REMOTEPROC=y +CONFIG_REMOTEPROC_CDEV=y +CONFIG_HOMO_REMOTEPROC=y +CONFIG_RPMSG_CHAR=m CONFIG_RPMSG_QCOM_GLINK_RPM=y CONFIG_SOUNDWIRE=m CONFIG_SOUNDWIRE_QCOM=m diff --git a/drivers/net/can/phytium/phytium_can.c b/drivers/net/can/phytium/phytium_can.c index e03e0c0d41..e94a7c66ed 100644 --- a/drivers/net/can/phytium/phytium_can.c +++ b/drivers/net/can/phytium/phytium_can.c @@ -437,6 +437,7 @@ static int phytium_can_poll(struct napi_struct *napi, int quota) struct net_device *dev = napi->dev; struct phytium_can_dev *cdev = netdev_priv(dev); int work_done; + unsigned long flags; netdev_dbg(dev, "The receive processing is going on !\n"); @@ -447,7 +448,9 @@ static int phytium_can_poll(struct napi_struct *napi, int quota) */ if (work_done >= 0 && work_done < quota) { napi_complete_done(napi, work_done); - phytium_can_enable_all_interrupts(cdev); + spin_lock_irqsave(&cdev->lock, flags); + phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_REIE); + spin_unlock_irqrestore(&cdev->lock, flags); } return work_done; @@ -465,8 +468,6 @@ static void phytium_can_write_frame(struct phytium_can_dev *cdev) data_len = can_len2dlc(cf->len); cdev->tx_skb = NULL; - phytium_can_clr_reg_bits(cdev, CAN_CTRL, CTRL_XFER); - /* Watch carefully on the bit sequence */ if (cf->can_id & CAN_EFF_FLAG) { /* Extended CAN ID format */ @@ -548,15 +549,10 @@ static void phytium_can_write_frame(struct phytium_can_dev *cdev) } stats->tx_bytes += cf->len; - can_put_echo_skb(skb, dev, cdev->tx_head % cdev->tx_max); - cdev->tx_head++; - - netif_stop_queue(dev); - /* triggers tranmission */ - phytium_can_set_reg_bits(cdev, CAN_CTRL, CTRL_TXREQ | CTRL_XFER); - + stats->tx_packets++; netdev_dbg(dev, "Trigger send message!\n"); - + can_put_echo_skb(skb, dev, 0); + can_get_echo_skb(dev, 0); return; } @@ -564,22 +560,28 @@ static netdev_tx_t phytium_can_tx_handler(struct phytium_can_dev *cdev) { struct net_device *dev = cdev->net; u32 tx_fifo_used; + unsigned long flags; - /* Check if the TX buffer is full */ - tx_fifo_used = (phytium_can_read(cdev, CAN_FIFO_CNT) & FIFO_CNT_TFN) >> 16; - if (tx_fifo_used == cdev->tx_max) { - netif_stop_queue(dev); - netdev_err(dev, "BUG!, TX FIFO full when queue awake!\n"); - return NETDEV_TX_BUSY; - } + phytium_can_write_frame(cdev); - if (cdev->tx_head == cdev->tx_tail) { - cdev->tx_head = 0; - cdev->tx_tail = 0; + /* Check if the TX buffer is full */ + tx_fifo_used = 4 * ((phytium_can_read(cdev, CAN_FIFO_CNT) & FIFO_CNT_TFN) >> 16); + if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) { + if (CAN_FIFO_BYTE_LEN - tx_fifo_used <= KEEP_CANFD_FIFO_MIN_LEN) { + netif_stop_queue(dev); + spin_lock_irqsave(&cdev->lock, flags); + cdev->is_stop_queue_flag = STOP_QUEUE_TRUE; + spin_unlock_irqrestore(&cdev->lock, flags); + } + } else { + if (CAN_FIFO_BYTE_LEN - tx_fifo_used <= KEEP_CAN_FIFO_MIN_LEN) { + netif_stop_queue(dev); + spin_lock_irqsave(&cdev->lock, flags); + cdev->is_stop_queue_flag = STOP_QUEUE_TRUE; + spin_unlock_irqrestore(&cdev->lock, flags); + } } - phytium_can_write_frame(cdev); - return NETDEV_TX_OK; } @@ -592,19 +594,29 @@ static void phytium_can_tx_interrupt(struct net_device *ndev, u32 isr) { struct phytium_can_dev *cdev = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; + u32 tx_fifo_used = 0; - while ((cdev->tx_head - cdev->tx_tail > 0) && (isr & INTR_TEIS)) { - phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_TEIC | INTR_REIC); - can_get_echo_skb(ndev, cdev->tx_tail % cdev->tx_max); - cdev->tx_tail++; - stats->tx_packets++; - isr = (phytium_can_read(cdev, CAN_INTR) & INTR_STATUS_MASK); + if (isr & INTR_TEIS) { + phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_TEIC); } + /* Check if the TX buffer is full */ + if (cdev->is_stop_queue_flag) { + tx_fifo_used = 4 * ((phytium_can_read(cdev, CAN_FIFO_CNT) & FIFO_CNT_TFN) >> 16); + if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) { + if (CAN_FIFO_BYTE_LEN - tx_fifo_used > KEEP_CANFD_FIFO_MIN_LEN) { + netif_wake_queue(ndev); + cdev->is_stop_queue_flag = STOP_QUEUE_FALSE; + } + } else { + if (CAN_FIFO_BYTE_LEN - tx_fifo_used > KEEP_CAN_FIFO_MIN_LEN) { + netif_wake_queue(ndev); + cdev->is_stop_queue_flag = STOP_QUEUE_FALSE; + } + } + } netdev_dbg(ndev, "Finish transform packets %lu\n", stats->tx_packets); - netdev_dbg(ndev, "\n-------------------\n"); can_led_event(ndev, CAN_LED_EVENT_TX); - netif_wake_queue(ndev); } static void phytium_can_err_interrupt(struct net_device *ndev, u32 isr) @@ -705,7 +717,7 @@ static irqreturn_t phytium_can_isr(int irq, void *dev_id) isr = phytium_can_read(cdev, CAN_INTR) & INTR_STATUS_MASK; if (!isr) return IRQ_NONE; - + spin_lock(&cdev->lock); /* Check for FIFO full interrupt and alarm */ if ((isr & INTR_RFIS)) { netdev_dbg(dev, "rx_fifo is full!.\n"); @@ -722,6 +734,7 @@ static irqreturn_t phytium_can_isr(int irq, void *dev_id) phytium_can_set_reg_bits(cdev, CAN_INTR, (INTR_EIC | INTR_RFIC | INTR_BOIC)); phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_EIE | INTR_BOIE); + spin_unlock(&cdev->lock); return IRQ_HANDLED; } @@ -736,7 +749,7 @@ static irqreturn_t phytium_can_isr(int irq, void *dev_id) phytium_can_set_reg_bits(cdev, CAN_INTR, INTR_REIC); napi_schedule(&cdev->napi); } - + spin_unlock(&cdev->lock); return IRQ_HANDLED; } @@ -864,7 +877,7 @@ static void phytium_can_stop(struct net_device *dev) /* Disable all interrupts */ phytium_can_disable_all_interrupt(cdev); - + /* Disable transfer and switch to receive-only mode */ ctrl = phytium_can_read(cdev, CAN_CTRL); ctrl &= ~(CTRL_XFER | CTRL_TXREQ); @@ -936,6 +949,7 @@ static int phytium_can_open(struct net_device *dev) can_led_event(dev, CAN_LED_EVENT_OPEN); napi_enable(&cdev->napi); + cdev->is_stop_queue_flag = STOP_QUEUE_FALSE; netif_start_queue(dev); return 0; @@ -1021,7 +1035,7 @@ static int phytium_can_dev_setup(struct phytium_can_dev *cdev) cdev->can.ctrlmode = CAN_CTRLMODE_FD; cdev->can.data_bittiming_const = cdev->bit_timing; } - + spin_lock_init(&cdev->lock); return 0; } diff --git a/drivers/net/can/phytium/phytium_can.h b/drivers/net/can/phytium/phytium_can.h index 3f125548c4..e8e5cff92d 100644 --- a/drivers/net/can/phytium/phytium_can.h +++ b/drivers/net/can/phytium/phytium_can.h @@ -23,6 +23,12 @@ #include #include +#define KEEP_CAN_FIFO_MIN_LEN 16 +#define KEEP_CANFD_FIFO_MIN_LEN 128 +#define CAN_FIFO_BYTE_LEN 256 +#define STOP_QUEUE_TRUE 1 +#define STOP_QUEUE_FALSE 0 + enum phytium_can_ip_type { PHYTIUM_CAN = 0, PHYTIUM_CANFD, @@ -35,9 +41,6 @@ struct phytium_can_devtype { struct phytium_can_dev { struct can_priv can; - unsigned int tx_head; - unsigned int tx_tail; - unsigned int tx_max; struct napi_struct napi; struct net_device *net; struct device *dev; @@ -46,11 +49,12 @@ struct phytium_can_dev { struct sk_buff *tx_skb; const struct can_bittiming_const *bit_timing; - + spinlock_t lock; int fdmode; u32 isr; u32 tx_fifo_depth; - + unsigned int is_stop_queue_flag; + struct completion comp; void __iomem *base; }; diff --git a/drivers/net/can/phytium/phytium_can_platform.c b/drivers/net/can/phytium/phytium_can_platform.c index 3a4f4b47c9..ce479af111 100644 --- a/drivers/net/can/phytium/phytium_can_platform.c +++ b/drivers/net/can/phytium/phytium_can_platform.c @@ -135,9 +135,6 @@ static int phytium_can_plat_probe(struct platform_device *pdev) } cdev->tx_fifo_depth = tx_fifo_depth; - cdev->tx_head = 0; - cdev->tx_tail = 0; - cdev->tx_max = tx_fifo_depth; if (devtype->cantype == PHYTIUM_CANFD) cdev->fdmode = 1; diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index d99548fb5d..b714bf090b 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -288,6 +288,12 @@ config TI_K3_R5_REMOTEPROC It's safe to say N here if you're not interested in utilizing a slave processor. +config HOMO_REMOTEPROC + bool "homogeneous remoteproc support" + select RPMSG_VIRTIO + help + Say y here to support homogeneous processors via the remote processor framework. + endif # REMOTEPROC endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index da2ace4ec8..9a5540d9a8 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -34,3 +34,4 @@ obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o obj-$(CONFIG_TI_K3_R5_REMOTEPROC) += ti_k3_r5_remoteproc.o +obj-$(CONFIG_HOMO_REMOTEPROC) += homo_remoteproc.o diff --git a/drivers/remoteproc/homo_remoteproc.c b/drivers/remoteproc/homo_remoteproc.c new file mode 100644 index 0000000000..056cabdd73 --- /dev/null +++ b/drivers/remoteproc/homo_remoteproc.c @@ -0,0 +1,349 @@ +/* + * Homogeneous Remote Processor Control Driver + * + * Copyright (c) 2022-2023 Phytium Technology Co., Ltd. + * Author: Shaojun Yang + * + * This program is free software; you can redistribute it and/or modify it under the terms + * of the GNU General Public License version 2 as published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "remoteproc_internal.h" + +#define RPROC_RESOURCE_ENTRIES 8 + +#define PSCI_VERSION 0x84000000 +#define CPU_SUSPEND 0xc4000001 +#define CPU_OFF 0x84000002 +#define CPU_ON 0xc4000003 +#define AFFINITY_INFO 0xc4000004 +#define MIGRATE 0xc4000005 + +/* Resource table for the homo remote processors */ +struct homo_resource_table { + unsigned int version; + unsigned int num; + unsigned int reserved[2]; + unsigned int offset[RPROC_RESOURCE_ENTRIES]; + + /* Note: linux kenrel 'struct fw_rsc_vdev' has no 'type' field, here add to align data structre */ + uint32_t type; + /* rpmsg vdev entry */ + struct fw_rsc_vdev rpmsg_vdev; + struct fw_rsc_vdev_vring rpmsg_vring0; + struct fw_rsc_vdev_vring rpmsg_vring1; +}; + +struct homo_rproc { + struct rproc *rproc; + struct homo_resource_table *rsc; + + u64 phys_addr; + void *addr; + u64 size; + + int irq; + int cpu; +}; + +static int homo_rproc_irq; +static struct homo_rproc *g_priv; +static struct work_struct workqueue; + +#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) (MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT) + +void gicv3_ipi_send_single(int irq, u64 mpidr) +{ + u16 tlist = 0; + u64 cluster_id; + u64 sgi1r; + + /* Ensure stores to Normal memory are visible to other CPUs before sending the IPI. */ + wmb(); + + cluster_id = mpidr & ~0xffUL; + tlist |= 1 << (mpidr & 0xf); + + /* Send the IPIs for the target list of this cluster */ + sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3) | + MPIDR_TO_SGI_AFFINITY(cluster_id, 2) | + irq << 24 | + MPIDR_TO_SGI_AFFINITY(cluster_id, 1) | tlist); + gic_write_sgi1r(sgi1r); + + /* Force the above writes to ICC_SGI1R_EL1 to be executed */ + isb(); +} + +static void homo_rproc_vq_irq(struct work_struct *work) +{ + struct homo_rproc *priv = g_priv; + struct homo_resource_table *rsc = priv->rsc; + struct rproc *rproc = priv->rproc; + + rproc_vq_interrupt(rproc, rsc->rpmsg_vring0.notifyid); +} + +static int homo_rproc_start(struct rproc *rproc) +{ + int err; + struct homo_rproc *priv = rproc->priv; + int phys_cpuid = cpu_logical_map(priv->cpu); + struct arm_smccc_res smc_res; + + err = psci_ops.affinity_info(phys_cpuid, 0); + if (err == 0) + remove_cpu(priv->cpu); + + INIT_WORK(&workqueue, homo_rproc_vq_irq); + + priv->rsc = (struct homo_resource_table *)rproc->table_ptr; + + /* ARMv8 requires to clean D-cache and invalidate I-cache for memory containing new instructions. */ + flush_icache_range((unsigned long)priv->addr, (unsigned long)(priv->addr + priv->size)); + + arm_smccc_smc(CPU_ON, phys_cpuid, (unsigned long long)priv->phys_addr, 0, 0, 0, 0, 0, &smc_res); + + return smc_res.a0; +} + +static int homo_rproc_stop(struct rproc *rproc) +{ + int err; + struct homo_rproc *priv = rproc->priv; + + err = psci_ops.affinity_info(cpu_logical_map(priv->cpu), 0); + if (err == 1) + add_cpu(priv->cpu); + + return 0; +} + +static void *homo_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) +{ + struct homo_rproc *priv = rproc->priv; + + return priv->addr + (da - rproc->bootaddr); +} + +static void homo_rproc_kick(struct rproc *rproc, int vqid) +{ + struct homo_rproc *priv = rproc->priv; + + if (rproc->state == RPROC_RUNNING) + gicv3_ipi_send_single(priv->irq, cpu_logical_map(priv->cpu)); + + return ; +} + +static const struct rproc_ops homo_rproc_ops = { + .start = homo_rproc_start, + .stop = homo_rproc_stop, + .kick = homo_rproc_kick, + .da_to_va = homo_rproc_da_to_va, +}; + +static void __iomem *homo_ioremap_prot(phys_addr_t addr, size_t size, pgprot_t prot) +{ + unsigned long offset, vaddr; + phys_addr_t last_addr; + struct vm_struct *area; + + /* Disallow wrap-around or zero size */ + last_addr = addr + size - 1; + if (!size || last_addr < addr) + return NULL; + + /* Page-align mappings */ + offset = addr & (~PAGE_MASK); + addr -= offset; + size = PAGE_ALIGN(size + offset); + + area = get_vm_area_caller(size, VM_IOREMAP, + __builtin_return_address(0)); + if (!area) + return NULL; + vaddr = (unsigned long)area->addr; + + if (ioremap_page_range(vaddr, vaddr + size, addr, prot)) { + free_vm_area(area); + return NULL; + } + + return (void __iomem *)(vaddr + offset); +} + +static irqreturn_t homo_rproc_irq_handler(int irq, void *data) +{ + schedule_work(&workqueue); + return IRQ_HANDLED; +} + +static int homo_rproc_starting_cpu(unsigned int cpu) +{ + enable_percpu_irq(homo_rproc_irq, irq_get_trigger_type(homo_rproc_irq)); + return 0; +} + +static int homo_rproc_dying_cpu(unsigned int cpu) +{ + disable_percpu_irq(homo_rproc_irq); + return 0; +} + +static int homo_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node, *p; + struct device_node *np_mem; + struct resource res; + struct rproc *rproc; + const char *fw_name; + struct homo_rproc *priv; + int ret; + unsigned int ipi, cpu; + struct of_phandle_args oirq; + + ret = rproc_of_parse_firmware(dev, 0, &fw_name); + if (ret) { + dev_err(dev, "failed to parse firmware-name property, ret = %d\n", ret); + return ret; + } + + rproc = rproc_alloc(dev, np->name, &homo_rproc_ops, fw_name, sizeof(*priv)); + if (!rproc) + return -ENOMEM; + + rproc->auto_boot = false; + rproc->has_iommu = false; + + platform_set_drvdata(pdev, rproc); + + priv = g_priv = rproc->priv; + priv->rproc = rproc; + + /* The following values can be modified through devicetree 'homo_rproc' node */ + if (of_property_read_u32(np, "remote-processor", &cpu)) { + dev_err(dev, "not found 'remote-processor' property\n"); + return -EINVAL; + } + + if (of_property_read_u32(np, "inter-processor-interrupt", &ipi)) { + dev_err(dev, "not found 'inter-processor-interrupt' property\n"); + return -EINVAL; + } + + /* The gic-v3 driver has registered the 0-7 range of SGI interrupt for system purpose */ + if (ipi < 8) { + dev_err(dev, "'inter-processor-interrupt' is %d, should be between 9~15\n", ipi); + return -EINVAL; + } + + priv->cpu = cpu; + priv->irq = ipi; + + dev_info(dev, "remote-processor = %d, inter-processor-interrupt = %d\n", cpu, ipi); + + np_mem = of_parse_phandle(np, "memory-region", 0); + ret = of_address_to_resource(np_mem, 0, &res); + if (ret) { + dev_err(dev, "can't find memory-region for Baremetal\n"); + return ret; + } + + priv->rsc = NULL; + priv->addr = NULL; + + priv->phys_addr = res.start; + priv->size = resource_size(&res); + + /* Map physical memory region reserved for homo remote processor. */ + priv->addr = homo_ioremap_prot(priv->phys_addr, priv->size, PAGE_KERNEL_EXEC); + if (!priv->addr) { + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; + } + dev_info(dev, "ioremap: phys_addr = %016llx, addr = %llx, size = %lld\n", + priv->phys_addr, (u64)(priv->addr), priv->size); + + /* Look for the interrupt parent. */ + p = of_irq_find_parent(np); + if (p == NULL) { + ret = -EINVAL; + goto err; + } + + oirq.np = p; + oirq.args_count = 1; + oirq.args[0] = ipi; + homo_rproc_irq = irq_create_of_mapping(&oirq); + if (homo_rproc_irq <= 0) { + ret = -EINVAL; + goto err; + } + + ret = request_percpu_irq(homo_rproc_irq, homo_rproc_irq_handler, "homo-rproc-ipi", &cpu_number); + if (ret) { + dev_err(dev, "failed to request percpu irq, status = %d\n", ret); + goto err; + } + + ret = cpuhp_setup_state(CPUHP_AP_HOMO_RPROC_STARTING, "remoteproc/homo_rproc:starting", homo_rproc_starting_cpu, homo_rproc_dying_cpu); + if (ret) { + dev_err(dev, "cpuhp setup state failed, status = %d\n", ret); + goto err; + } + + ret = rproc_add(rproc); + if (ret) { + dev_err(dev, "failed to add register device with remoteproc core, status = %d\n", ret); + goto err; + } + + return 0; + +err: + vunmap((void *)((unsigned long)priv->addr & PAGE_MASK)); + return ret; +} + +static int homo_rproc_remove(struct platform_device *pdev) +{ + struct rproc *rproc = platform_get_drvdata(pdev); + + rproc_del(rproc); + rproc_free(rproc); + + return 0; +} + +static const struct of_device_id homo_rproc_ids[] = { + { .compatible = "homo,rproc", }, + { } +}; +MODULE_DEVICE_TABLE(of, homo_rproc_ids); + +static struct platform_driver homo_rproc_driver = { + .probe = homo_rproc_probe, + .remove = homo_rproc_remove, + .driver = { + .name = "homo-rproc", + .of_match_table = of_match_ptr(homo_rproc_ids), + }, +}; +module_platform_driver(homo_rproc_driver); + +MODULE_DESCRIPTION("Homogeneous Remote Processor Control Driver"); +MODULE_AUTHOR("Shaojun Yang "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-phytium-pci.c b/drivers/spi/spi-phytium-pci.c index cdd6671e48..4b83bc1b5d 100644 --- a/drivers/spi/spi-phytium-pci.c +++ b/drivers/spi/spi-phytium-pci.c @@ -85,16 +85,14 @@ static void phytium_spi_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int spi_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct phytium_spi *fts = spi_master_get_devdata(master); + struct phytium_spi *fts = dev_get_drvdata(dev); return phytium_spi_suspend_host(fts); } static int spi_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct phytium_spi *fts = spi_master_get_devdata(master); + struct phytium_spi *fts = dev_get_drvdata(dev); return phytium_spi_resume_host(fts); } diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index fc945f9df2..0ced817d4c 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -195,6 +195,7 @@ enum cpuhp_state { CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 30, CPUHP_AP_X86_HPET_ONLINE, CPUHP_AP_X86_KVM_CLK_ONLINE, + CPUHP_AP_HOMO_RPROC_STARTING, CPUHP_AP_ACTIVE, CPUHP_ONLINE, }; diff --git a/sound/pci/hda/hda_phytium.c b/sound/pci/hda/hda_phytium.c index c134675145..17dcf92d54 100644 --- a/sound/pci/hda/hda_phytium.c +++ b/sound/pci/hda/hda_phytium.c @@ -833,9 +833,6 @@ static int azx_first_init(struct azx *chip) bus->cmd_resend = 1; - if (azx_acquire_irq(chip, 0) < 0) - return -EBUSY; - synchronize_irq(bus->irq); gcap = azx_readw(chip, GCAP); @@ -899,6 +896,9 @@ static int azx_first_init(struct azx *chip) return -ENODEV; } + if (azx_acquire_irq(chip, 0) < 0) + return -EBUSY; + strcpy(card->driver, "ft-hda"); strcpy(card->shortname, "ft-hda"); snprintf(card->longname, sizeof(card->longname), -- Gitee