diff --git a/arch/arm/boot/dts/rv1106-evb-cam.dtsi b/arch/arm/boot/dts/rv1106-evb-cam.dtsi index d13073bb0507..7d6793a71919 100644 --- a/arch/arm/boot/dts/rv1106-evb-cam.dtsi +++ b/arch/arm/boot/dts/rv1106-evb-cam.dtsi @@ -55,6 +55,21 @@ remote-endpoint = <&imx415_out>; data-lanes = <1 2>; }; + csi_dphy_input7: endpoint@7 { + reg = <7>; + remote-endpoint = <&sc450ai_out>; + data-lanes = <1 2>; + }; + csi_dphy_input8: endpoint@8 { + reg = <8>; + remote-endpoint = <&sc401ai_out>; + data-lanes = <1 2>; + }; + csi_dphy_input9: endpoint@9 { + reg = <9>; + remote-endpoint = <&sc200ai_out>; + data-lanes = <1 2>; + }; }; port@1 { @@ -229,6 +244,72 @@ }; }; }; + + sc450ai: sc450ai@30 { + compatible = "smartsens,sc450ai"; + status = "okay"; + reg = <0x30>; + clocks = <&cru MCLK_REF_MIPI0>; + clock-names = "xvclk"; + reset-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; + pwdn-gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&mipi_refclk_out0>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "CMK-OT2119-PC1"; + rockchip,camera-module-lens-name = "30IRC-F16"; + port { + sc450ai_out: endpoint { + remote-endpoint = <&csi_dphy_input7>; + data-lanes = <1 2>; + }; + }; + }; + + sc401ai: sc401ai@30 { + compatible = "smartsens,sc401ai"; + status = "okay"; + reg = <0x30>; + clocks = <&cru MCLK_REF_MIPI0>; + clock-names = "xvclk"; + reset-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; + pwdn-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&mipi_refclk_out0>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "CMK-OT2115-PC1"; + rockchip,camera-module-lens-name = "30IRC-F16"; + port { + sc401ai_out: endpoint { + remote-endpoint = <&csi_dphy_input8>; + data-lanes = <1 2>; + }; + }; + }; + + sc200ai: sc200ai@30 { + compatible = "smartsens,sc200ai"; + status = "okay"; + reg = <0x30>; + clocks = <&cru MCLK_REF_MIPI0>; + clock-names = "xvclk"; + reset-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; + pwdn-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&mipi_refclk_out0>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "CMK-OT2115-PC1"; + rockchip,camera-module-lens-name = "30IRC-F16"; + port { + sc200ai_out: endpoint { + remote-endpoint = <&csi_dphy_input9>; + data-lanes = <1 2>; + }; + }; + }; }; &mipi0_csi2 { diff --git a/arch/arm/boot/dts/rv1106-tb-nofastae-emmc.dtsi b/arch/arm/boot/dts/rv1106-tb-nofastae-emmc.dtsi index 1095b35564d4..b9e0c778ae1a 100644 --- a/arch/arm/boot/dts/rv1106-tb-nofastae-emmc.dtsi +++ b/arch/arm/boot/dts/rv1106-tb-nofastae-emmc.dtsi @@ -11,14 +11,16 @@ reg = <0x3f000 0x00001000>; }; - mmc_idmac: mmc@100000 { - reg = <0x00100000 0x00100000>; + mmc_idmac: mmc@80000 { + reg = <0x0080000 0x17e000>; }; }; thunder_boot_mmc: thunder-boot-mmc { compatible = "rockchip,thunder-boot-mmc"; reg = <0xffa90000 0x4000>; + clocks = <&cru HCLK_EMMC>, <&cru CCLK_SRC_EMMC>; + clock-names = "biu", "ciu"; memory-region-src = <&ramdisk_c>; memory-region-dst = <&ramdisk_r>; memory-region-idmac = <&mmc_idmac>; diff --git a/arch/arm/boot/dts/rv1106-thunder-boot-emmc.dtsi b/arch/arm/boot/dts/rv1106-thunder-boot-emmc.dtsi index 208cb559d7b5..90e7954ea877 100644 --- a/arch/arm/boot/dts/rv1106-thunder-boot-emmc.dtsi +++ b/arch/arm/boot/dts/rv1106-thunder-boot-emmc.dtsi @@ -11,14 +11,16 @@ reg = <0x3f000 0x00001000>; }; - mmc_idmac: mmc@100000 { - reg = <0x00100000 0x00100000>; + mmc_idmac: mmc@80000 { + reg = <0x0080000 0x17e000>; }; }; thunder_boot_mmc: thunder-boot-mmc { compatible = "rockchip,thunder-boot-mmc"; reg = <0xffa90000 0x4000>; + clocks = <&cru HCLK_EMMC>, <&cru CCLK_SRC_EMMC>; + clock-names = "biu", "ciu"; memory-region-src = <&ramdisk_c>; memory-region-dst = <&ramdisk_r>; memory-region-idmac = <&mmc_idmac>; diff --git a/arch/arm/configs/rv1106-evb.config b/arch/arm/configs/rv1106-evb.config index 7e71c6bab354..5ce66f6953f6 100644 --- a/arch/arm/configs/rv1106-evb.config +++ b/arch/arm/configs/rv1106-evb.config @@ -39,8 +39,11 @@ CONFIG_VFAT_FS=y CONFIG_VIDEO_GC2053=m CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_OS04A10=m +CONFIG_VIDEO_SC200AI=m CONFIG_VIDEO_SC3336=m +CONFIG_VIDEO_SC401AI=m CONFIG_VIDEO_SC4336=m +CONFIG_VIDEO_SC450AI=m CONFIG_VIDEO_SC530AI=m CONFIG_WIRELESS=y CONFIG_WLAN=y diff --git a/arch/arm64/boot/dts/rockchip/rk3567-evb2-lp4x-v10-dual-lvds.dts b/arch/arm64/boot/dts/rockchip/rk3567-evb2-lp4x-v10-dual-lvds.dts index d50ccd30a08c..c4516902c9cc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3567-evb2-lp4x-v10-dual-lvds.dts +++ b/arch/arm64/boot/dts/rockchip/rk3567-evb2-lp4x-v10-dual-lvds.dts @@ -16,6 +16,7 @@ model = "Rockchip RK3567 EVB2 LP4X V10 Board"; compatible = "rockchip,rk3567-evb2-lp4x-v10", "rockchip,rk3567"; + /* panel: claa070wp03xg */ panel { compatible = "simple-panel"; backlight = <&backlight>; @@ -40,7 +41,7 @@ vback-porch = <4>; vfront-porch = <2>; hsync-len = <8>; - vsync-len = <2>; + vsync-len = <8>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi index d38f2c2ca3ae..eae796d48b58 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi @@ -9,6 +9,7 @@ #include "rk3568-evb1-ddr4-v10.dtsi" / { + /* panel: claa070wp03xg */ panel { compatible = "simple-panel"; backlight = <&backlight>; @@ -33,7 +34,7 @@ vback-porch = <4>; vfront-porch = <2>; hsync-len = <8>; - vsync-len = <2>; + vsync-len = <8>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c index e20c9077145f..cd7b08f704d3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c @@ -56,7 +56,7 @@ static int get_afbc_size(uint32_t width, uint32_t height, uint32_t bpp) int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_count) { int flags; - int bpp = 32; + int bpp; const char *ptr; char file_name[100]; int width; @@ -66,6 +66,10 @@ int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_co loff_t pos = 0; bpp = rockchip_drm_get_bpp(dump_info->format); + if (!bpp) { + DRM_WARN("invalid bpp %d\n", bpp); + return 0; + } if (dump_info->yuv_format) { u8 hsub = dump_info->format->hsub; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 032117943e6a..74731091c68e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -469,6 +469,11 @@ static void vop_load_sdr2hdr_table(struct vop *vop, uint32_t cmd) uint32_t sdr2hdr_eotf_oetf_yn[65]; uint32_t sdr2hdr_oetf_dx_dxpow[64]; + if (cmd != SDR2HDR_FOR_BT2020 && cmd != SDR2HDR_FOR_HDR && cmd != SDR2HDR_FOR_HLG_HDR) { + DRM_WARN("unknown sdr2hdr oetf: %d\n", cmd); + return; + } + for (i = 0; i < 65; i++) { if (cmd == SDR2HDR_FOR_BT2020) sdr2hdr_eotf_oetf_yn[i] = diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 252aba42b33b..efcf8139dc31 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -5147,7 +5147,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s actual_w = drm_rect_width(src) >> 16; actual_h = drm_rect_height(src) >> 16; - if (!actual_w || !actual_h) { + if (!actual_w || !actual_h || !bpp) { vop2_win_disable(win, true); return; } @@ -5268,10 +5268,6 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s /* AFBC pic_vir_width is count by pixel, this is different * with WIN_VIR_STRIDE. */ - if (!bpp) { - WARN(1, "bpp is zero\n"); - bpp = 1; - } stride = (fb->pitches[0] << 3) / bpp; if ((stride & 0x3f) && (vpstate->xmirror_en || vpstate->rotate_90_en || vpstate->rotate_270_en)) @@ -6588,7 +6584,7 @@ static size_t vop2_plane_line_bandwidth(struct drm_plane_state *pstate) size_t bandwidth; if (src_width <= 0 || src_height <= 0 || dst_width <= 0 || - dst_height <= 0) + dst_height <= 0 || !bpp) return 0; bandwidth = src_width * bpp / 8; diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 4ec3ead28a70..b5cf30999179 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -74,8 +74,8 @@ config RPMSG_QCOM_SMD providing communication channels to remote processors in Qualcomm platforms. -config RPMSG_ROCKCHIP - tristate "Rockchip Platform RPMsg Support" +config RPMSG_ROCKCHIP_MBOX + tristate "Rockchip Platform RPMsg Mailbox Mode Support" depends on ARCH_ROCKCHIP depends on MAILBOX depends on ROCKCHIP_MBOX @@ -83,11 +83,20 @@ config RPMSG_ROCKCHIP select VIRTIO help Say y here to enable support for The Remote Processors Messasing - in Rockchip Platform. + using mailbox mode in Rockchip Platform. + +config RPMSG_ROCKCHIP_SOFTIRQ + tristate "Rockchip Platform RPMsg Soft IRQ Mode Support" + depends on ARCH_ROCKCHIP + select RPMSG + select VIRTIO + help + Say y here to enable support for The Remote Processors Messasing + using softirq mode in Rockchip Platform. config RPMSG_ROCKCHIP_TEST tristate "Rockchip RPMsg Test" - depends on RPMSG_ROCKCHIP + depends on (RPMSG_ROCKCHIP_MBOX || RPMSG_ROCKCHIP_SOFTIRQ) help Say y here to enable Rockchip RPMsg Test. diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index 4b9a1b89d1cc..3119bb97df6b 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK) += qcom_glink.o obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o -obj-$(CONFIG_RPMSG_ROCKCHIP) += rockchip_rpmsg.o +obj-$(CONFIG_RPMSG_ROCKCHIP_MBOX) += rockchip_rpmsg_mbox.o +obj-$(CONFIG_RPMSG_ROCKCHIP_SOFTIRQ) += rockchip_rpmsg_softirq.o obj-$(CONFIG_RPMSG_ROCKCHIP_TEST) += rockchip_rpmsg_test.o obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o diff --git a/drivers/rpmsg/rockchip_rpmsg.c b/drivers/rpmsg/rockchip_rpmsg_mbox.c similarity index 98% rename from drivers/rpmsg/rockchip_rpmsg.c rename to drivers/rpmsg/rockchip_rpmsg_mbox.c index 897712542ef7..c70e89b023d7 100644 --- a/drivers/rpmsg/rockchip_rpmsg.c +++ b/drivers/rpmsg/rockchip_rpmsg_mbox.c @@ -383,8 +383,16 @@ free_channel: static int rockchip_rpmsg_remove(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct rk_rpmsg_dev *rpdev = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < rpdev->vdev_nums; i++) + unregister_virtio_device(&rpdev->rpvdev[i]->vdev); + + of_reserved_mem_device_release(dev); + mbox_free_channel(rpdev->mbox_rx_chan); mbox_free_channel(rpdev->mbox_tx_chan); diff --git a/drivers/rpmsg/rockchip_rpmsg_softirq.c b/drivers/rpmsg/rockchip_rpmsg_softirq.c new file mode 100644 index 000000000000..df3c77b25ffa --- /dev/null +++ b/drivers/rpmsg/rockchip_rpmsg_softirq.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Remote Processors Messaging Platform Support. + * + * Copyright (c) 2023 Rockchip Electronics Co. Ltd. + * Author: Hongming Zou + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpmsg_internal.h" + +struct rk_virtio_dev { + struct virtio_device vdev; + unsigned int vring[2]; + struct virtqueue *vq[2]; + unsigned int base_queue_id; + int num_of_vqs; + struct rk_rpmsg_dev *rpdev; +}; + +struct rk_rpmsg_irqs { + int irq_tx; + int irq_rx; +}; + +#define to_rk_rpvdev(vd) container_of(vd, struct rk_virtio_dev, vdev) + +struct rk_rpmsg_dev { + struct platform_device *pdev; + int vdev_nums; + unsigned int link_id; + int first_notify; + u32 flags; + struct rk_virtio_dev *rpvdev[RPMSG_MAX_INSTANCE_NUM]; + struct rk_rpmsg_irqs irqs; +}; + +struct rk_rpmsg_vq_info { + u32 queue_id; + void *vring_addr; + struct rk_rpmsg_dev *rpdev; +}; + +static irqreturn_t rk_rpmsg_rx_callback(int irq, void *_pdev) +{ + u32 link_id; + struct platform_device *pdev = _pdev; + struct rk_virtio_dev *rpvdev; + struct rk_rpmsg_dev *rpdev = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + link_id = rpdev->link_id; + rpvdev = rpdev->rpvdev[0]; + rpdev->flags |= RPMSG_REMOTE_IS_READY; + dev_dbg(dev, "rpmsg master: rx link_id=0x%x flag=0x%x\n", link_id, rpdev->flags); + vring_interrupt(0, rpvdev->vq[0]); + + return IRQ_HANDLED; +} + +static bool rk_rpmsg_notify(struct virtqueue *vq) +{ + struct rk_rpmsg_vq_info *rpvq = vq->priv; + struct rk_rpmsg_dev *rpdev = rpvq->rpdev; + struct platform_device *pdev = rpdev->pdev; + struct device *dev = &pdev->dev; + struct irq_chip *chip; + + chip = irq_get_chip(rpdev->irqs.irq_tx); + + dev_dbg(dev, "queue_id-0x%x virt_vring_addr 0x%p\n", + rpvq->queue_id, rpvq->vring_addr); + + if ((rpdev->first_notify == 0) && (rpvq->queue_id % 2 == 0)) { + /* first_notify is used in the master init handshake phase. */ + dev_dbg(dev, "rpmsg first_notify\n"); + rpdev->first_notify++; + } else if (rpvq->queue_id % 2 == 0) { + /* tx done is not supported, so ignored */ + return true; + } + + if (chip && chip->irq_retrigger) + chip->irq_retrigger(irq_get_irq_data(rpdev->irqs.irq_tx)); + + return true; +} + +static struct virtqueue *rk_rpmsg_find_vq(struct virtio_device *vdev, + unsigned int index, + void (*callback)(struct virtqueue *vq), + const char *name, + bool ctx) +{ + struct rk_virtio_dev *rpvdev = to_rk_rpvdev(vdev); + struct rk_rpmsg_dev *rpdev = rpvdev->rpdev; + struct platform_device *pdev = rpdev->pdev; + struct device *dev = &pdev->dev; + struct rk_rpmsg_vq_info *rpvq; + struct virtqueue *vq; + int ret; + + rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL); + if (!rpvq) + return ERR_PTR(-ENOMEM); + + rpdev->flags &= (~RPMSG_CACHED_VRING); + rpvq->vring_addr = (__force void *) ioremap(rpvdev->vring[index], RPMSG_VRING_SIZE); + if (!rpvq->vring_addr) { + ret = -ENOMEM; + goto free_rpvq; + } + dev_dbg(dev, "vring%d: phys 0x%x, virt 0x%p\n", index, + rpvdev->vring[index], rpvq->vring_addr); + + memset_io(rpvq->vring_addr, 0, RPMSG_VRING_SIZE); + + vq = vring_new_virtqueue(index, RPMSG_BUF_COUNT, RPMSG_VRING_ALIGN, vdev, true, ctx, + rpvq->vring_addr, rk_rpmsg_notify, callback, name); + if (!vq) { + dev_err(dev, "vring_new_virtqueue failed\n"); + ret = -ENOMEM; + goto unmap_vring; + } + + rpvdev->vq[index] = vq; + vq->priv = rpvq; + + rpvq->queue_id = rpvdev->base_queue_id + index; + rpvq->rpdev = rpdev; + + return vq; + +unmap_vring: + iounmap((__force void __iomem *) rpvq->vring_addr); +free_rpvq: + kfree(rpvq); + return ERR_PTR(ret); +} + +static u8 rk_rpmsg_get_status(struct virtio_device *vdev) +{ + /* TODO: */ + return 0; +} + +static void rk_rpmsg_set_status(struct virtio_device *vdev, u8 status) +{ + /* TODO: */ +} + +static void rk_rpmsg_reset(struct virtio_device *vdev) +{ + /* TODO: */ +} + +static void rk_rpmsg_del_vqs(struct virtio_device *vdev) +{ + struct virtqueue *vq, *n; + + list_for_each_entry_safe(vq, n, &vdev->vqs, list) { + struct rk_rpmsg_vq_info *rpvq = vq->priv; + + iounmap(rpvq->vring_addr); + vring_del_virtqueue(vq); + kfree(rpvq); + } +} + +static int rk_rpmsg_find_vqs(struct virtio_device *vdev, unsigned int nvqs, + struct virtqueue *vqs[], + vq_callback_t *callbacks[], + const char * const names[], + const bool *ctx, + struct irq_affinity *desc) +{ + struct rk_virtio_dev *rpvdev = to_rk_rpvdev(vdev); + int i, ret; + + /* Each rpmsg instance has two virtqueues. vqs[0] is rvq and vqs[1] is tvq */ + if (nvqs != 2) + return -EINVAL; + + for (i = 0; i < nvqs; ++i) { + vqs[i] = rk_rpmsg_find_vq(vdev, i, callbacks[i], names[i], + ctx ? ctx[i] : false); + if (IS_ERR(vqs[i])) { + ret = PTR_ERR(vqs[i]); + goto error; + } + } + + rpvdev->num_of_vqs = nvqs; + + return 0; + +error: + rk_rpmsg_del_vqs(vdev); + + return ret; +} + +static u64 rk_rpmsg_get_features(struct virtio_device *vdev) +{ + return RPMSG_VIRTIO_RPMSG_F_NS; +} + +static int rk_rpmsg_finalize_features(struct virtio_device *vdev) +{ + vring_transport_features(vdev); + + return 0; +} + +static void rk_rpmsg_vdev_release(struct device *dev) +{ +} + +static struct virtio_config_ops rk_rpmsg_config_ops = { + .get_status = rk_rpmsg_get_status, + .set_status = rk_rpmsg_set_status, + .reset = rk_rpmsg_reset, + .find_vqs = rk_rpmsg_find_vqs, + .del_vqs = rk_rpmsg_del_vqs, + .get_features = rk_rpmsg_get_features, + .finalize_features = rk_rpmsg_finalize_features, +}; + +static int rk_set_vring_phy_buf(struct platform_device *pdev, + struct rk_rpmsg_dev *rpdev, int vdev_nums) +{ + struct device *dev = &pdev->dev; + struct resource *res; + resource_size_t size; + unsigned int start, end; + int i, ret = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + size = resource_size(res); + start = res->start; + end = res->start + size; + for (i = 0; i < vdev_nums; i++) { + rpdev->rpvdev[i] = devm_kzalloc(dev, sizeof(struct rk_virtio_dev), + GFP_KERNEL); + if (!rpdev->rpvdev[i]) + return -ENOMEM; + + rpdev->rpvdev[i]->vring[0] = start; + rpdev->rpvdev[i]->vring[1] = start + RPMSG_VRING_SIZE; + start += RPMSG_VRING_OVERHEAD; + if (start > end) { + dev_err(dev, "Too small memory size %x!\n", (u32)size); + ret = -EINVAL; + break; + } + } + } else { + return -ENOMEM; + } + + return ret; +} + +static int rockchip_rpmsg_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rk_rpmsg_dev *rpdev = NULL; + + int i, ret = 0; + + rpdev = devm_kzalloc(dev, sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) + return -ENOMEM; + + dev_info(dev, "rockchip rpmsg platform probe.\n"); + rpdev->pdev = pdev; + rpdev->first_notify = 0; + + ret = device_property_read_u32(dev, "rockchip,link-id", &rpdev->link_id); + if (ret) { + dev_err(dev, "failed to get link_id, ret %d\n", ret); + + return ret; + } + ret = device_property_read_u32(dev, "rockchip,vdev-nums", &rpdev->vdev_nums); + if (ret) { + dev_info(dev, "vdev-nums default 1\n"); + rpdev->vdev_nums = 1; + + return ret; + } + if (rpdev->vdev_nums > RPMSG_MAX_INSTANCE_NUM) { + dev_err(dev, "vdev-nums exceed the max %d\n", RPMSG_MAX_INSTANCE_NUM); + + return -EINVAL; + } + + rpdev->irqs.irq_tx = platform_get_irq(pdev, 0); + if (rpdev->irqs.irq_tx < 0) + return rpdev->irqs.irq_tx; + + rpdev->irqs.irq_rx = platform_get_irq(pdev, 1); + if (rpdev->irqs.irq_rx < 0) + return rpdev->irqs.irq_rx; + + ret = devm_request_threaded_irq(&pdev->dev, rpdev->irqs.irq_rx, NULL, rk_rpmsg_rx_callback, + IRQF_ONESHOT, "rockchip-rpmsg", pdev); + if (ret) { + dev_err(dev, "could not install irq"); + + return ret; + } + + ret = rk_set_vring_phy_buf(pdev, rpdev, rpdev->vdev_nums); + if (ret) { + dev_err(dev, "No vring buffer.\n"); + + return -EINVAL; + } + if (of_reserved_mem_device_init(dev)) { + dev_info(dev, "No shared DMA pool.\n"); + rpdev->flags &= (~RPMSG_SHARED_DMA_POOL); + } else { + rpdev->flags |= RPMSG_SHARED_DMA_POOL; + } + + for (i = 0; i < rpdev->vdev_nums; i++) { + dev_info(dev, "rpdev vdev%d: vring0 0x%x, vring1 0x%x\n", + i, rpdev->rpvdev[i]->vring[0], rpdev->rpvdev[i]->vring[1]); + rpdev->rpvdev[i]->vdev.id.device = VIRTIO_ID_RPMSG; + rpdev->rpvdev[i]->vdev.config = &rk_rpmsg_config_ops; + rpdev->rpvdev[i]->vdev.dev.parent = dev; + rpdev->rpvdev[i]->vdev.dev.release = rk_rpmsg_vdev_release; + rpdev->rpvdev[i]->base_queue_id = i * 2; + rpdev->rpvdev[i]->rpdev = rpdev; + + ret = register_virtio_device(&rpdev->rpvdev[i]->vdev); + if (ret) { + dev_err(dev, "fail to register rpvdev: %d\n", ret); + goto free_reserved_mem; + } + } + + platform_set_drvdata(pdev, rpdev); + + return ret; + +free_reserved_mem: + if (rpdev->flags & RPMSG_SHARED_DMA_POOL) + of_reserved_mem_device_release(dev); + + return ret; +} + +static int rockchip_rpmsg_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rk_rpmsg_dev *rpdev = platform_get_drvdata(pdev); + + int i; + + for (i = 0; i < rpdev->vdev_nums; i++) + unregister_virtio_device(&rpdev->rpvdev[i]->vdev); + + of_reserved_mem_device_release(dev); + + return 0; +} + +static const struct of_device_id rockchip_rpmsg_match[] = { + { .compatible = "rockchip,rpmsg-softirq", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, rockchip_rpmsg_match); + +static struct platform_driver rockchip_rpmsg_softirq_driver = { + .probe = rockchip_rpmsg_probe, + .remove = rockchip_rpmsg_remove, + .driver = { + .name = "rockchip-rpmsg-softirq", + .of_match_table = rockchip_rpmsg_match, + }, +}; +module_platform_driver(rockchip_rpmsg_softirq_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Rockchip Using Softirq Mode Remote Processors Messaging Platform Support"); +MODULE_AUTHOR("Hongming Zou "); diff --git a/drivers/soc/rockchip/rockchip_thunderboot_mmc.c b/drivers/soc/rockchip/rockchip_thunderboot_mmc.c index ba16186e79e0..10618811f0e9 100644 --- a/drivers/soc/rockchip/rockchip_thunderboot_mmc.c +++ b/drivers/soc/rockchip/rockchip_thunderboot_mmc.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2020 Rockchip Electronics Co., Ltd. */ +#include #include #include #include @@ -27,6 +28,8 @@ static int rk_tb_mmc_thread(void *p) struct resource *res; struct device_node *rds, *rdd, *dma; struct device *dev = &pdev->dev; + struct clk_bulk_data *clk_bulks; + int clk_num; u32 status; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -40,6 +43,18 @@ static int rk_tb_mmc_thread(void *p) rdd = of_parse_phandle(dev->of_node, "memory-region-dst", 0); dma = of_parse_phandle(dev->of_node, "memory-region-idmac", 0); + clk_num = clk_bulk_get_all(&pdev->dev, &clk_bulks); + if (clk_num >= 0) { + ret = clk_bulk_prepare_enable(clk_num, clk_bulks); + if (ret) { + dev_err(&pdev->dev, "failed to enable clocks\n"); + return ret; + } + } else { + dev_err(&pdev->dev, "failed to get clks property\\n"); + return clk_num; + } + if (readl_poll_timeout(regs + SDMMC_STATUS, status, !(status & (BIT(10) | GENMASK(7, 4))), 100, 500 * USEC_PER_MSEC)) @@ -95,6 +110,8 @@ static int rk_tb_mmc_thread(void *p) } out: + clk_bulk_disable_unprepare(clk_num, clk_bulks); + clk_bulk_put_all(clk_num, clk_bulks); of_node_put(rds); of_node_put(rdd); of_node_put(dma);