From c6e1bad408eedb6fe080f04a18a0c14d2dbfc260 Mon Sep 17 00:00:00 2001 From: Sungjoon Moon Date: Fri, 20 Mar 2026 01:04:16 +0900 Subject: [PATCH 1/9] drm/canaan: add K230 display controller driver DRM/KMS driver for the Canaan K230 Video Output and MIPI DSI controllers. Supports atomic modesetting with 2 video and 4 OSD planes, dynamic DSI PHY clock configuration, and CMA-backed framebuffer scanout. Ported from the K230 SDK with fixes for kernel 6.12 API changes. Reference: https://github.com/ruyisdk/linux-xuantie-kernel/commit/e8dde9a551c2 https://github.com/ruyisdk/linux-xuantie-kernel/commit/e7bde087e74f https://github.com/ruyisdk/linux-xuantie-kernel/commit/ae4a7e6518cd --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/canaan/Kconfig | 34 ++ drivers/gpu/drm/canaan/Makefile | 10 + drivers/gpu/drm/canaan/canaan_crtc.c | 158 +++++ drivers/gpu/drm/canaan/canaan_crtc.h | 28 + drivers/gpu/drm/canaan/canaan_drv.c | 422 ++++++++++++++ drivers/gpu/drm/canaan/canaan_drv.h | 15 + drivers/gpu/drm/canaan/canaan_dsi.c | 646 ++++++++++++++++++++ drivers/gpu/drm/canaan/canaan_dsi.h | 59 ++ drivers/gpu/drm/canaan/canaan_phy.c | 278 +++++++++ drivers/gpu/drm/canaan/canaan_plane.c | 133 +++++ drivers/gpu/drm/canaan/canaan_plane.h | 41 ++ drivers/gpu/drm/canaan/canaan_vo.c | 713 +++++++++++++++++++++++ drivers/gpu/drm/canaan/canaan_vo.h | 48 ++ drivers/gpu/drm/canaan/canaan_vo_regs.h | 225 +++++++ drivers/gpu/drm/canaan/canaan_vo_table.h | 123 ++++ 17 files changed, 2936 insertions(+) create mode 100644 drivers/gpu/drm/canaan/Kconfig create mode 100644 drivers/gpu/drm/canaan/Makefile create mode 100644 drivers/gpu/drm/canaan/canaan_crtc.c create mode 100644 drivers/gpu/drm/canaan/canaan_crtc.h create mode 100644 drivers/gpu/drm/canaan/canaan_drv.c create mode 100644 drivers/gpu/drm/canaan/canaan_drv.h create mode 100644 drivers/gpu/drm/canaan/canaan_dsi.c create mode 100644 drivers/gpu/drm/canaan/canaan_dsi.h create mode 100644 drivers/gpu/drm/canaan/canaan_phy.c create mode 100644 drivers/gpu/drm/canaan/canaan_plane.c create mode 100644 drivers/gpu/drm/canaan/canaan_plane.h create mode 100644 drivers/gpu/drm/canaan/canaan_vo.c create mode 100644 drivers/gpu/drm/canaan/canaan_vo.h create mode 100644 drivers/gpu/drm/canaan/canaan_vo_regs.h create mode 100644 drivers/gpu/drm/canaan/canaan_vo_table.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index cf5bc77e2362c4..4926b1f4d0cda0 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -349,6 +349,8 @@ source "drivers/gpu/drm/i2c/Kconfig" source "drivers/gpu/drm/arm/Kconfig" +source "drivers/gpu/drm/canaan/Kconfig" + source "drivers/gpu/drm/radeon/Kconfig" source "drivers/gpu/drm/amd/amdgpu/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 784229d4504dcb..b5d24ddf6046f0 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -156,6 +156,7 @@ obj-y += tests/ obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o obj-y += arm/ +obj-$(CONFIG_DRM_CANAAN) += canaan/ obj-y += display/ obj-$(CONFIG_DRM_TTM) += ttm/ obj-$(CONFIG_DRM_SCHED) += scheduler/ diff --git a/drivers/gpu/drm/canaan/Kconfig b/drivers/gpu/drm/canaan/Kconfig new file mode 100644 index 00000000000000..bb0fa297c80ee4 --- /dev/null +++ b/drivers/gpu/drm/canaan/Kconfig @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_CANAAN + bool "DRM Support for Canaan K230 Display Controller" + depends on OF + depends on COMMON_CLK + depends on DRM + select DRM_KMS_HELPER + select DRM_KMS_DMA_HELPER + select DRM_GEM_DMA_HELPER + select VIDEOMODE_HELPERS + default ARCH_CANAAN + help + Choose this option if you have a Canaan K230 soc chipset. + This driver provides kernel mode setting and buffer + management to userspace. This driver does not provide + 2D or 3D acceleration; acceleration is performed by other + IP found on the SoC. + +if DRM_CANAAN + +config DRM_CANAAN_DSI + bool "Canaan K230 MIPI-DSI Controller Support" + select DRM_MIPI_DSI + select DRM_DISPLAY_HELPER + select DRM_BRIDGE_CONNECTOR + default DRM_CANAAN + help + Choose this option if you have a Canaan K230 soc chipset. + This driver provides MIPI-DSI controller for DRM. + This driver does not provide 2D or 3D acceleration; + acceleration is performed by other + IP found on the SoC. + +endif diff --git a/drivers/gpu/drm/canaan/Makefile b/drivers/gpu/drm/canaan/Makefile new file mode 100644 index 00000000000000..e547cca4c4da14 --- /dev/null +++ b/drivers/gpu/drm/canaan/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +canaan-drm-y := \ + canaan_drv.o \ + canaan_vo.o \ + canaan_crtc.o \ + canaan_plane.o \ + canaan_phy.o + +obj-$(CONFIG_DRM_CANAAN) += canaan-drm.o +obj-$(CONFIG_DRM_CANAAN_DSI) += canaan_dsi.o diff --git a/drivers/gpu/drm/canaan/canaan_crtc.c b/drivers/gpu/drm/canaan/canaan_crtc.c new file mode 100644 index 00000000000000..b815a4d9e833fb --- /dev/null +++ b/drivers/gpu/drm/canaan/canaan_crtc.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022, Canaan Bright Sight Co., Ltd + * + * All enquiries to https://www.canaan-creative.com/ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "canaan_vo.h" +#include "canaan_crtc.h" +#include "canaan_plane.h" + +static int canaan_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct canaan_crtc *canaan_crtc = to_canaan_crtc(crtc); + struct canaan_vo *vo = canaan_crtc->vo; + + DRM_DEBUG_DRIVER("Enable vblank on CRTC:%d\n", crtc->base.id); + return canaan_vo_enable_vblank(vo); +} + +static void canaan_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct canaan_crtc *canaan_crtc = to_canaan_crtc(crtc); + struct canaan_vo *vo = canaan_crtc->vo; + + DRM_DEBUG_DRIVER("Disable vblank on CRTC:%d\n", crtc->base.id); + canaan_vo_disable_vblank(vo); +} + +static void canaan_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *old_crtc_state) +{ + struct canaan_crtc *canaan_crtc = to_canaan_crtc(crtc); + struct canaan_vo *vo = canaan_crtc->vo; + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; + + DRM_DEBUG_DRIVER("Enable the CRTC:%d\n", crtc->base.id); + + canaan_vo_enable_crtc(vo, canaan_crtc, adjusted_mode); + drm_crtc_vblank_on(crtc); +} + +static void canaan_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *old_crtc_state) +{ + struct canaan_crtc *canaan_crtc = to_canaan_crtc(crtc); + struct canaan_vo *vo = canaan_crtc->vo; + + DRM_DEBUG_DRIVER("Disable the CRTC:%d\n", crtc->base.id); + + /* Send any pending event before disabling vblank */ + if (crtc->state->event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + crtc->state->event = NULL; + } + + drm_crtc_vblank_off(crtc); + canaan_vo_disable_crtc(vo, canaan_crtc); +} + +static void canaan_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *old_crtc_state) +{ + struct canaan_crtc *canaan_crtc = to_canaan_crtc(crtc); + struct canaan_vo *vo = canaan_crtc->vo; + struct drm_pending_vblank_event *event = crtc->state->event; + + DRM_DEBUG_DRIVER("Flush the configuration\n"); + canaan_vo_flush_config(vo); + + if (event) { + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_arm_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + crtc->state->event = NULL; + } +} + +static const struct drm_crtc_funcs canaan_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = canaan_crtc_enable_vblank, + .disable_vblank = canaan_crtc_disable_vblank, +}; + +static const struct drm_crtc_helper_funcs canaan_crtc_helper_funcs = { + .atomic_enable = canaan_crtc_atomic_enable, + .atomic_disable = canaan_crtc_atomic_disable, + .atomic_flush = canaan_crtc_atomic_flush, +}; + +struct canaan_crtc *canaan_crtc_create(struct drm_device *drm_dev, + struct drm_plane *primary, + struct drm_plane *cursor, + struct canaan_vo *vo) +{ + int ret = 0; + struct canaan_crtc *canaan_crtc = NULL; + struct drm_crtc *crtc = NULL; + struct device *dev = vo->dev; + + canaan_crtc = devm_kzalloc(dev, sizeof(struct canaan_crtc), GFP_KERNEL); + if (!canaan_crtc) + return ERR_PTR(-ENOMEM); + canaan_crtc->vo = vo; + crtc = &canaan_crtc->base; + + ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, + &canaan_crtc_funcs, "canaan_crtc"); + if (ret) { + DRM_DEV_ERROR(dev, "Failed to init CRTC\n"); + return ERR_PTR(ret); + } + + drm_crtc_helper_add(crtc, &canaan_crtc_helper_funcs); + + drm_mode_crtc_set_gamma_size(crtc, 256); + drm_crtc_enable_color_mgmt(crtc, 0, false, 256); + DRM_DEBUG_DRIVER("Create the CRTC:%d\n", crtc->base.id); + + return canaan_crtc; +} diff --git a/drivers/gpu/drm/canaan/canaan_crtc.h b/drivers/gpu/drm/canaan/canaan_crtc.h new file mode 100644 index 00000000000000..8f6af93309ef7e --- /dev/null +++ b/drivers/gpu/drm/canaan/canaan_crtc.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022, Canaan Bright Sight Co., Ltd + * + * All enquiries to https://www.canaan-creative.com/ + * + */ + +#ifndef __CANAAN_CRTC_H__ +#define __CANAAN_CRTC_H__ + +struct canaan_crtc { + struct drm_crtc base; + struct canaan_vo *vo; + struct drm_pending_vblank_event *event; +}; + +static inline struct canaan_crtc *to_canaan_crtc(struct drm_crtc *crtc) +{ + return container_of(crtc, struct canaan_crtc, base); +} + +struct canaan_crtc *canaan_crtc_create(struct drm_device *drm_dev, + struct drm_plane *primary, + struct drm_plane *cursor, + struct canaan_vo *vo); + +#endif /* __CANAAN_CRTC_H__ */ diff --git a/drivers/gpu/drm/canaan/canaan_drv.c b/drivers/gpu/drm/canaan/canaan_drv.c new file mode 100644 index 00000000000000..4af5db6f36e23d --- /dev/null +++ b/drivers/gpu/drm/canaan/canaan_drv.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022, Canaan Bright Sight Co., Ltd + * + * All enquiries to https://www.canaan-creative.com/ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "canaan_drv.h" +#include "canaan_vo.h" + +static int canaan_drm_open(struct inode *inode, struct file *filp); +static int canaan_drm_release(struct inode *inode, struct file *filp); + +int canaan_drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct *vma) +{ + struct drm_gem_object *obj = &dma_obj->base; + int ret; + + /* + * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the + * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map + * the whole buffer. + */ + vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); + vm_flags_mod(vma, VM_DONTEXPAND, VM_PFNMAP); + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + ret = remap_pfn_range( + vma, + vma->vm_start, + dma_obj->dma_addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot + ); + + if (ret) + drm_gem_vm_close(vma); + + return ret; +} + +static int canaan_drm_gem_dma_object_mmap(struct drm_gem_object *obj, + struct vm_area_struct *vma) +{ + struct drm_gem_dma_object *dma_obj = to_drm_gem_dma_obj(obj); + + return canaan_drm_gem_dma_mmap(dma_obj, vma); +} + +static const struct drm_gem_object_funcs drm_gem_dma_default_funcs = { + .free = drm_gem_dma_object_free, + .print_info = drm_gem_dma_object_print_info, + .get_sg_table = drm_gem_dma_object_get_sg_table, + .vmap = drm_gem_dma_object_vmap, + .mmap = canaan_drm_gem_dma_object_mmap, + .vm_ops = &drm_gem_dma_vm_ops, +}; + +static struct drm_gem_dma_object * +__drm_gem_dma_create(struct drm_device *drm, size_t size, bool private) +{ + struct drm_gem_dma_object *dma_obj; + struct drm_gem_object *gem_obj; + int ret = 0; + + if (drm->driver->gem_create_object) { + gem_obj = drm->driver->gem_create_object(drm, size); + if (IS_ERR(gem_obj)) + return ERR_CAST(gem_obj); + dma_obj = to_drm_gem_dma_obj(gem_obj); + } else { + dma_obj = kzalloc(sizeof(*dma_obj), GFP_KERNEL); + if (!dma_obj) + return ERR_PTR(-ENOMEM); + gem_obj = &dma_obj->base; + } + + if (!gem_obj->funcs) + gem_obj->funcs = &drm_gem_dma_default_funcs; + + if (drm_gem_object_init(drm, gem_obj, size)) + goto error; + + ret = drm_gem_create_mmap_offset(gem_obj); + if (ret) { + drm_gem_object_release(gem_obj); + goto error; + } + + return dma_obj; + +error: + kfree(dma_obj); + return ERR_PTR(ret); +} + +static struct drm_gem_dma_object *canaan_drm_gem_dma_create(struct drm_device *drm, + size_t size) +{ + struct drm_gem_dma_object *dma_obj; + int ret; + + size = round_up(size, PAGE_SIZE); + + dma_obj = __drm_gem_dma_create(drm, size, false); + if (IS_ERR(dma_obj)) + return dma_obj; + + dma_obj->vaddr = dma_alloc_coherent(drm->dev, size, + &dma_obj->dma_addr, + GFP_KERNEL | __GFP_NOWARN); + if (!dma_obj->vaddr) { + drm_dbg(drm, "failed to allocate buffer with size %zu\n", + size); + ret = -ENOMEM; + goto error; + } + + return dma_obj; + +error: + drm_gem_object_put(&dma_obj->base); + return ERR_PTR(ret); +} + +static int canaan_drm_dumb_create(struct drm_file *file_priv, + struct drm_device *drm, + struct drm_mode_create_dumb *args) +{ + struct drm_gem_dma_object *dma_obj; + struct drm_gem_object *gem_obj; + int ret; + + args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + args->size = args->pitch * args->height; + + dma_obj = canaan_drm_gem_dma_create(drm, args->size); + if (IS_ERR(dma_obj)) + return PTR_ERR(dma_obj); + + gem_obj = &dma_obj->base; + ret = drm_gem_handle_create(file_priv, gem_obj, &args->handle); + drm_gem_object_put(gem_obj); + + return ret; +} + +static const struct file_operations canaan_drm_fops = { + .owner = THIS_MODULE, + .open = canaan_drm_open, + .release = canaan_drm_release, + .unlocked_ioctl = drm_ioctl, + .compat_ioctl = drm_compat_ioctl, + .poll = drm_poll, + .read = drm_read, + .llseek = noop_llseek, + .mmap = drm_gem_mmap, + .fop_flags = FOP_UNSIGNED_OFFSET, + DRM_GEM_DMA_UNMAPPED_AREA_FOPS +}; + +static struct drm_driver canaan_drm_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + .dumb_create = canaan_drm_dumb_create, + .gem_prime_import_sg_table = drm_gem_dma_prime_import_sg_table_vmap, + .fops = &canaan_drm_fops, + .name = "canaan-drm", + .desc = "Canaan K230 DRM driver", + .date = "20230501", + .major = 1, + .minor = 0, +}; + +static const struct drm_mode_config_funcs canaan_drm_mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static const struct drm_mode_config_helper_funcs + canaan_drm_mode_config_helpers = { + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, + }; + +static struct device *disp_dev; + +static int canaan_drm_open(struct inode *inode, struct file *filp) +{ + int ret; + + pm_runtime_get_sync(disp_dev); + ret = drm_open(inode, filp); + + return ret; +} + +static int canaan_drm_release(struct inode *inode, struct file *filp) +{ + int ret; + + ret = drm_release(inode, filp); + + return ret; +} + +static int canaan_drm_bind(struct device *dev) +{ + int ret = 0; + struct drm_device *drm_dev; + + drm_dev = drm_dev_alloc(&canaan_drm_driver, dev); + if (IS_ERR(drm_dev)) + return PTR_ERR(drm_dev); + dev_set_drvdata(dev, drm_dev); + + drm_mode_config_init(drm_dev); + drm_dev->mode_config.min_width = 16; + drm_dev->mode_config.min_height = 16; + drm_dev->mode_config.max_width = 4096; + drm_dev->mode_config.max_height = 4096; + drm_dev->mode_config.normalize_zpos = true; + drm_dev->mode_config.funcs = &canaan_drm_mode_config_funcs; + drm_dev->mode_config.helper_private = &canaan_drm_mode_config_helpers; + + /* Power on DISP domain before accessing hardware */ + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + DRM_DEV_ERROR(dev, "Failed to power on display: %d\n", ret); + goto cleanup_mode_config; + } + + ret = component_bind_all(dev, drm_dev); + if (ret) { + DRM_DEV_ERROR(dev, "Failed to bind all components\n"); + goto put_runtime; + } + + ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc); + if (ret) { + DRM_DEV_ERROR(dev, "Failed to init vblank\n"); + goto unbind_all; + } + + drm_mode_config_reset(drm_dev); + drm_kms_helper_poll_init(drm_dev); + + ret = drm_dev_register(drm_dev, 0); + if (ret) { + DRM_DEV_ERROR(dev, "Failed to register drm device\n"); + goto finish_poll; + } + + drm_fbdev_dma_setup(drm_dev, 24); + DRM_DEV_INFO(dev, "Canaan K230 DRM driver register successfully\n"); + + return 0; + +finish_poll: + drm_kms_helper_poll_fini(drm_dev); +unbind_all: + component_unbind_all(dev, drm_dev); +put_runtime: + pm_runtime_put(dev); +cleanup_mode_config: + drm_mode_config_cleanup(drm_dev); + + dev_set_drvdata(dev, NULL); + drm_dev_put(drm_dev); + return ret; +} + +static void canaan_drm_unbind(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + + drm_dev_unregister(drm_dev); + drm_kms_helper_poll_fini(drm_dev); + drm_atomic_helper_shutdown(drm_dev); + component_unbind_all(dev, drm_dev); + drm_mode_config_cleanup(drm_dev); + dev_set_drvdata(dev, NULL); + drm_dev_put(drm_dev); + pm_runtime_put(dev); +} + +static const struct component_master_ops canaan_drm_master_ops = { + .bind = canaan_drm_bind, + .unbind = canaan_drm_unbind, +}; + +static struct platform_driver *const component_drivers[] = { + &canaan_vo_driver, + &canaan_dsi_driver, +}; + +static int compare_dev(struct device *dev, void *data) +{ + return dev == (struct device *)data; +} + +static struct component_match *canaan_drm_match_add(struct device *dev) +{ + int i = 0; + struct component_match *match = NULL; + + for (i = 0; i < ARRAY_SIZE(component_drivers); i++) { + struct device_driver *driver = &component_drivers[i]->driver; + struct device *p = NULL, *d; + + while ((d = platform_find_device_by_driver(p, driver))) { + put_device(p); + component_match_add(dev, &match, compare_dev, d); + p = d; + } + put_device(p); + } + + return match ?: ERR_PTR(-ENODEV); +} + +static int canaan_drm_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct component_match *match = NULL; + int ret; + + disp_dev = dev; + pm_runtime_enable(disp_dev); + match = canaan_drm_match_add(dev); + if (IS_ERR(match)) { + pm_runtime_disable(disp_dev); + return PTR_ERR(match); + } + + ret = component_master_add_with_match(dev, &canaan_drm_master_ops, + match); + if (ret) + pm_runtime_disable(disp_dev); + + return ret; +} + +static void canaan_drm_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &canaan_drm_master_ops); + pm_runtime_disable(&pdev->dev); +} + +static const struct of_device_id canaan_drm_of_table[] = { + { + .compatible = "canaan,display-subsystem", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, canaan_drm_of_table); + +static struct platform_driver canaan_drm_platform_driver = { + .probe = canaan_drm_platform_probe, + .remove = canaan_drm_platform_remove, + .driver = { + .name = "canaan-drm", + .of_match_table = canaan_drm_of_table, + }, +}; + +static int __init canaan_drm_init(void) +{ + int ret = 0; + + ret = platform_register_drivers(component_drivers, + ARRAY_SIZE(component_drivers)); + if (ret) + return ret; + + ret = platform_driver_register(&canaan_drm_platform_driver); + if (ret) + platform_unregister_drivers(component_drivers, + ARRAY_SIZE(component_drivers)); + + return ret; +} + +static void __exit canaan_drm_exit(void) +{ + platform_unregister_drivers(component_drivers, + ARRAY_SIZE(component_drivers)); + platform_driver_unregister(&canaan_drm_platform_driver); +} + +module_init(canaan_drm_init); +module_exit(canaan_drm_exit); + +MODULE_DESCRIPTION("Canaan K230 DRM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/canaan/canaan_drv.h b/drivers/gpu/drm/canaan/canaan_drv.h new file mode 100644 index 00000000000000..646a25453ec08a --- /dev/null +++ b/drivers/gpu/drm/canaan/canaan_drv.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022, Canaan Bright Sight Co., Ltd + * + * All enquiries to https://www.canaan-creative.com/ + * + */ + +#ifndef __CANAAN_DRV_H__ +#define __CANAAN_DRV_H__ + +extern struct platform_driver canaan_vo_driver; +extern struct platform_driver canaan_dsi_driver; + +#endif /* __CANAAN_DRV_H__ */ diff --git a/drivers/gpu/drm/canaan/canaan_dsi.c b/drivers/gpu/drm/canaan/canaan_dsi.c new file mode 100644 index 00000000000000..9f3f75c89fcbba --- /dev/null +++ b/drivers/gpu/drm/canaan/canaan_dsi.c @@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022, Canaan Bright Sight Co., Ltd + * + * All enquiries to https://www.canaan-creative.com/ + * + */ + +#include "drm/drm_bridge.h" +#include "drm/drm_of.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "canaan_dsi.h" +#include