diff --git a/MAINTAINERS b/MAINTAINERS index 25f0a4957f41..dd3cc8255d99 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14110,3 +14110,7 @@ M: Guosong Zhou F: drivers/amlogic/media/video_processor/Kconfig F: drivers/amlogic/media/video_processor/Makefile F: drivers/amlogic/media/video_processor/pic_dev/* + +AMLOGIC DRM DRIVER +M: Sky Zhou +F: driver/amlogic/drm/* diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_2g_buildroot.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_2g_buildroot.dts index 0fd842e43d53..16fef2940816 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_2g_buildroot.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_2g_buildroot.dts @@ -37,6 +37,7 @@ }; ion_dev { compatible = "amlogic, ion_dev"; + memory-region = <&ion_reserved>; }; memory@00000000 { device_type = "memory"; @@ -61,12 +62,11 @@ reg = <0x0 0x05300000 0x0 0x2000000>; no-map; }; - fb_reserved:linux,meson-fb { + ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2400000>; + size = <0x0 0x8000000>; alignment = <0x0 0x400000>; - alloc-ranges = <0x0 0x7dc00000 0x0 0x2400000>; }; //don't put other dts in front of fb_reserved @@ -692,7 +692,6 @@ meson-fb { compatible = "amlogic, meson-fb"; - memory-region = <&fb_reserved>; dev_name = "meson-fb"; status = "okay"; interrupts = <0 3 1 diff --git a/drivers/amlogic/drm/Kconfig b/drivers/amlogic/drm/Kconfig index 8e5aa22fe395..6b2df202e23a 100644 --- a/drivers/amlogic/drm/Kconfig +++ b/drivers/amlogic/drm/Kconfig @@ -6,3 +6,31 @@ config DRM_MESON select DRM_GEM_CMA_HELPER select VIDEOMODE_HELPERS select REGMAP_MMIO + +config DRM_MESON_BYPASS_MODE + bool "use the drm display path, but all the implements in other drivers." + default y + depends on DRM_MESON + help + The MESON DRM want to rewrite all the display component,its a big job, + and will meet a lot of bugs which are already handled before. + We add bypass mode to implment drm based on amlogic existing driver, + it should be easier and more robust. + +config DRM_MESON_USE_ION + bool "gem use ion to alloc/free graphic buffer." + default y + depends on DRM_MESON + help + MESON DRM use CMA HELPER to manage framebuffer. + It need reserve memory in CMA pool. + We implement GEM to allocate/free framebuffer from ion. + For dumb used by displaycontrol we alloc from the ION CMA HEAP. + For dumb used by app, we can alloc from the ION. + SYSTEM HEAP which dont need reserve memory. + +config DRM_MESON_EMULATE_FBDEV + bool "emulate framebuffer dev by drm." + default n + help + Emulate framebuffer device for device which need use fbdev api. diff --git a/drivers/amlogic/drm/Makefile b/drivers/amlogic/drm/Makefile index 93c47c42ba35..8cd1b99f9435 100644 --- a/drivers/amlogic/drm/Makefile +++ b/drivers/amlogic/drm/Makefile @@ -1,5 +1,15 @@ -meson-y := meson_drv.o meson_gem.o meson_dmabuf.o -#meson-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_plane.o meson_crtc.o meson_venc_cvbs.o +meson-y := meson_drv.o + +ifeq ($(CONFIG_DRM_MESON_BYPASS_MODE),y) + meson-y += am_meson_plane.o am_meson_crtc.o am_meson_hdmi.o + ccflags-y += -Idrivers/amlogic/media/osd/ +else + meson-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_plane.o meson_crtc.o meson_venc_cvbs.o +endif + +ifeq ($(CONFIG_DRM_MESON_USE_ION),y) + meson-y += am_meson_gem.o am_meson_fb.o + ccflags-y += -Idrivers/staging/android/ +endif obj-$(CONFIG_DRM_MESON) += meson.o -ccflags-y += -Idrivers/staging/android/ diff --git a/drivers/amlogic/drm/am_meson_crtc.c b/drivers/amlogic/drm/am_meson_crtc.c new file mode 100644 index 000000000000..66654e8413ea --- /dev/null +++ b/drivers/amlogic/drm/am_meson_crtc.c @@ -0,0 +1,247 @@ +/* + * drivers/amlogic/drm/am_meson_crtc.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include +#include +#include +#include + +/* Amlogic Headers */ +#include + +#include "meson_crtc.h" +#include "osd_drm.h" + + +#define to_am_meson_crtc(x) container_of(x, struct am_meson_crtc, base) + +struct am_vout_mode { + char name[DRM_DISPLAY_MODE_LEN]; + enum vmode_e mode; + int width, height, vrefresh; + unsigned int flags; +}; + +static struct am_vout_mode am_vout_modes[] = { + { "1080p60hz", VMODE_HDMI, 1920, 1080, 60, 0}, + { "1080p30hz", VMODE_HDMI, 1920, 1080, 30, 0}, + { "1080p50hz", VMODE_HDMI, 1920, 1080, 50, 0}, + { "1080p25hz", VMODE_HDMI, 1920, 1080, 25, 0}, + { "1080p24hz", VMODE_HDMI, 1920, 1080, 24, 0}, + { "2160p30hz", VMODE_HDMI, 3840, 2160, 30, 0}, + { "2160p60hz", VMODE_HDMI, 3840, 2160, 60, 0}, + { "2160p50hz", VMODE_HDMI, 3840, 2160, 50, 0}, + { "2160p25hz", VMODE_HDMI, 3840, 2160, 25, 0}, + { "2160p24hz", VMODE_HDMI, 3840, 2160, 24, 0}, + { "1080i60hz", VMODE_HDMI, 1920, 1080, 60, DRM_MODE_FLAG_INTERLACE}, + { "1080i50hz", VMODE_HDMI, 1920, 1080, 50, DRM_MODE_FLAG_INTERLACE}, + { "720p60hz", VMODE_HDMI, 1280, 720, 60, 0}, + { "720p50hz", VMODE_HDMI, 1280, 720, 50, 0}, + { "480p60hz", VMODE_HDMI, 720, 480, 60, 0}, + { "480i60hz", VMODE_HDMI, 720, 480, 60, DRM_MODE_FLAG_INTERLACE}, + { "576p50hz", VMODE_HDMI, 720, 576, 50, 0}, + { "576i50hz", VMODE_HDMI, 720, 576, 50, DRM_MODE_FLAG_INTERLACE}, + { "480p60hz", VMODE_HDMI, 720, 480, 60, 0}, +}; + +char *am_meson_crtc_get_voutmode(struct drm_display_mode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(am_vout_modes); i++) { + if ((am_vout_modes[i].width == mode->hdisplay) + && (am_vout_modes[i].height == mode->vdisplay) + && (am_vout_modes[i].vrefresh == mode->vrefresh) + && (am_vout_modes[i].flags == + (mode->flags&DRM_MODE_FLAG_INTERLACE))) + return am_vout_modes[i].name; + } + return NULL; +} + +struct am_vpp { +}; + +struct am_vout { +}; + +struct am_meson_crtc { + struct drm_crtc base; + struct meson_drm *priv; + + struct drm_pending_vblank_event *event; + + struct am_vpp vpp; + struct am_vout vout; +}; + +void am_meson_crtc_handle_vsync(struct am_meson_crtc *amcrtc) +{ + unsigned long flags; + struct drm_crtc *crtc; + + crtc = &amcrtc->base; + drm_crtc_handle_vblank(crtc); + + spin_lock_irqsave(&crtc->dev->event_lock, flags); + if (amcrtc->event) { + drm_crtc_send_vblank_event(crtc, amcrtc->event); + drm_crtc_vblank_put(crtc); + amcrtc->event = NULL; + } + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); +} + +int am_meson_crtc_set_mode(struct drm_mode_set *set) +{ + struct am_meson_crtc *amcrtc; + int ret; + + DRM_DEBUG_DRIVER("am_crtc_set_mode\n"); + + amcrtc = to_am_meson_crtc(set->crtc); + ret = drm_atomic_helper_set_config(set); + + return ret; +} + +static const struct drm_crtc_funcs am_meson_crtc_funcs = { + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .destroy = drm_crtc_cleanup, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .set_config = am_meson_crtc_set_mode, +}; + +static bool am_meson_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + //DRM_INFO("am_meson_crtc_mode_fixup !!\n"); + + return true; +} + +void am_meson_crtc_enable(struct drm_crtc *crtc) +{ + enum vmode_e mode; + int ret = 0; + char *name; + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; + + if (!adjusted_mode) { + DRM_ERROR("meson_crtc_enable fail, unsupport mode:%s\n", + adjusted_mode->name); + return; + } + //DRM_INFO("meson_crtc_enable %s\n", adjusted_mode->name); + name = am_meson_crtc_get_voutmode(adjusted_mode); + + mode = validate_vmode(name); + if (mode == VMODE_MAX) { + DRM_ERROR("no matched vout mode\n"); + return; + } + + vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &mode); + ret = set_current_vmode(mode); + if (ret) + DRM_ERROR("new mode %s set error\n", name); + else + DRM_INFO("new mode %s set ok\n", name); + vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &mode); +} + +void am_meson_crtc_disable(struct drm_crtc *crtc) +{ + //DRM_INFO("meson_crtc_disable!!\n"); +} + +void am_meson_crtc_commit(struct drm_crtc *crtc) +{ + //DRM_INFO("am_meson_crtc_commit!!\n"); +} + +void am_meson_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct am_meson_crtc *amcrtc; + unsigned long flags; + + amcrtc = to_am_meson_crtc(crtc); + + if (crtc->state->event) { + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irqsave(&crtc->dev->event_lock, flags); + amcrtc->event = crtc->state->event; + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + crtc->state->event = NULL; + } +} + +void am_meson_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ +} + +static const struct drm_crtc_helper_funcs am_crtc_helper_funcs = { + .enable = am_meson_crtc_enable, + .disable = am_meson_crtc_disable, + .commit = am_meson_crtc_commit, + .mode_fixup = am_meson_crtc_mode_fixup, + .atomic_begin = am_meson_crtc_atomic_begin, + .atomic_flush = am_meson_crtc_atomic_flush, +}; + +int meson_crtc_create(struct meson_drm *priv) +{ + struct am_meson_crtc *amcrtc; + struct drm_crtc *crtc; + int ret; + + DRM_DEBUG("amlogic meson_crtc_create\n"); + amcrtc = devm_kzalloc(priv->drm->dev, sizeof(*amcrtc), + GFP_KERNEL); + if (!amcrtc) + return -ENOMEM; + + amcrtc->priv = priv; + crtc = &amcrtc->base; + ret = drm_crtc_init_with_planes(priv->drm, crtc, + priv->primary_plane, priv->cursor_plane, + &am_meson_crtc_funcs, "amlogic vpu"); + if (ret) { + dev_err(priv->drm->dev, "Failed to init CRTC\n"); + return ret; + } + + drm_crtc_helper_add(crtc, &am_crtc_helper_funcs); + osd_drm_init(); + + priv->crtc = crtc; + return 0; +} + +void meson_crtc_irq(struct meson_drm *priv) +{ + struct am_meson_crtc *amcrtc = to_am_meson_crtc(priv->crtc); + + osd_drm_vsync_isr_handler(); + am_meson_crtc_handle_vsync(amcrtc); +} + diff --git a/drivers/amlogic/drm/am_meson_fb.c b/drivers/amlogic/drm/am_meson_fb.c new file mode 100644 index 000000000000..16cdb5852791 --- /dev/null +++ b/drivers/amlogic/drm/am_meson_fb.c @@ -0,0 +1,80 @@ +/* + * drivers/amlogic/drm/am_meson_fb.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include "am_meson_fb.h" + +#define to_am_meson_fb(x) container_of(x, struct am_meson_fb, base) + +void am_meson_fb_destroy(struct drm_framebuffer *framebuffer) +{ + struct am_meson_fb *meson_fb = to_am_meson_fb(framebuffer); + + drm_gem_object_unreference_unlocked(&meson_fb->bufp->base); + drm_framebuffer_cleanup(framebuffer); + kfree(meson_fb); +} + +int am_meson_fb_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + DRM_INFO("ERROR: am_meson_fb_create_handle NOT implement.\n"); + return 0; +} + +struct drm_framebuffer_funcs am_meson_fb_funcs = { + .create_handle = am_meson_fb_create_handle, //must for fbdev emulate + .destroy = am_meson_fb_destroy, +}; + +struct drm_framebuffer *am_meson_fb_create(struct drm_device *dev, + struct drm_file *file_priv, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct am_meson_fb *meson_fb = 0; + struct drm_gem_object *obj = 0; + struct am_meson_gem_object *meson_gem; + int ret; + + meson_fb = kzalloc(sizeof(*meson_fb), GFP_KERNEL); + if (!meson_fb) + return ERR_PTR(-ENOMEM); + + /* only support one handle now.*/ + obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]); + if (!obj) { + dev_err(dev->dev, "Failed to lookup GEM handle\n"); + kfree(meson_fb); + return ERR_PTR(-ENOMEM); + } + + meson_gem = container_of(obj, struct am_meson_gem_object, base); + meson_fb->bufp = meson_gem; + + drm_helper_mode_fill_fb_struct(&meson_fb->base, mode_cmd); + + ret = drm_framebuffer_init(dev, &meson_fb->base, &am_meson_fb_funcs); + if (ret) { + dev_err(dev->dev, + "Failed to initialize framebuffer: %d\n", + ret); + drm_gem_object_unreference(obj); + kfree(meson_fb); + return ERR_PTR(ret); + } + + return &meson_fb->base; +} diff --git a/drivers/amlogic/drm/am_meson_fb.h b/drivers/amlogic/drm/am_meson_fb.h new file mode 100644 index 000000000000..4b63e589d24f --- /dev/null +++ b/drivers/amlogic/drm/am_meson_fb.h @@ -0,0 +1,35 @@ +/* + * drivers/amlogic/drm/am_meson_fb.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef __AM_MESON_FB_H +#define __AM_MESON_FB_H +#include +#include +#include +#include + +#include "am_meson_gem.h" + +struct am_meson_fb { + struct drm_framebuffer base; + struct am_meson_gem_object *bufp; +}; + +struct drm_framebuffer *am_meson_fb_create(struct drm_device *dev, + struct drm_file *file_priv, + const struct drm_mode_fb_cmd2 *mode_cmd); +#endif diff --git a/drivers/amlogic/drm/am_meson_gem.c b/drivers/amlogic/drm/am_meson_gem.c new file mode 100644 index 000000000000..afe404b7c3fe --- /dev/null +++ b/drivers/amlogic/drm/am_meson_gem.c @@ -0,0 +1,497 @@ +/* + * drivers/amlogic/drm/am_meson_gem.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "meson_drv.h" +#include "am_meson_gem.h" + +#define to_am_meson_gem_obj(x) container_of(x, struct am_meson_gem_object, base) + +static int am_meson_gem_alloc_ion_buff( + struct ion_client *client, + struct am_meson_gem_object *meson_gem_obj, + int flags) +{ + struct ion_handle *handle; + bool bscatter = false; + + if (!client) + return -EINVAL; + + if (!meson_gem_obj) + return -EINVAL; + + //TODO,check flags to set different ion heap type. + handle = ion_alloc(client, meson_gem_obj->base.size, + 0, (1 << ION_HEAP_TYPE_DMA), 0); + if (IS_ERR(handle)) { + handle = ion_alloc(client, meson_gem_obj->base.size, + 0, (1 << ION_HEAP_TYPE_SYSTEM), 0); + if (IS_ERR(handle)) { + DRM_ERROR("am_meson_gem_alloc_ion_buff FAILED.\n"); + return -ENOMEM; + } + + bscatter = true; + } + + meson_gem_obj->handle = handle; + meson_gem_obj->bscatter = bscatter; + DRM_DEBUG("%s: allocate handle (%p).\n", + __func__, meson_gem_obj->handle); + return 0; +} + +static void am_meson_gem_free_ion_buf( + struct drm_device *dev, + struct am_meson_gem_object *meson_gem_obj) +{ + struct ion_client *client = NULL; + + if (meson_gem_obj->handle) { + DRM_DEBUG("am_meson_gem_free_ion_buf free handle (%p).\n", + meson_gem_obj->handle); + client = meson_gem_obj->handle->client; + ion_free(client, meson_gem_obj->handle); + meson_gem_obj->handle = NULL; + } else { + DRM_ERROR("meson_gem_obj handle is null\n"); + } +} + +static struct am_meson_gem_object *am_meson_gem_object_create( + struct drm_device *dev, + unsigned int flags, + unsigned long size, + struct ion_client *client) +{ + struct am_meson_gem_object *meson_gem_obj = NULL; + int ret; + + if (!size) { + DRM_ERROR("invalid size.\n"); + return ERR_PTR(-EINVAL); + } + + meson_gem_obj = kzalloc(sizeof(*meson_gem_obj), GFP_KERNEL); + if (!meson_gem_obj) + return ERR_PTR(-ENOMEM); + + ret = drm_gem_object_init(dev, &meson_gem_obj->base, size); + if (ret < 0) { + DRM_ERROR("failed to initialize gem object\n"); + goto error; + } + + ret = am_meson_gem_alloc_ion_buff(client, meson_gem_obj, flags); + if (ret < 0) { + drm_gem_object_release(&meson_gem_obj->base); + goto error; + } + + return meson_gem_obj; + +error: + kfree(meson_gem_obj); + return ERR_PTR(ret); +} + +void am_meson_gem_object_free(struct drm_gem_object *obj) +{ + struct am_meson_gem_object *meson_gem_obj = to_am_meson_gem_obj(obj); + + DRM_DEBUG("am_meson_gem_object_free %p handle count = %d\n", + meson_gem_obj, obj->handle_count); + + if (obj->import_attach) + drm_prime_gem_destroy(obj, meson_gem_obj->sgt); + else + am_meson_gem_free_ion_buf(obj->dev, meson_gem_obj); + + drm_gem_free_mmap_offset(obj); + + /* release file pointer to gem object. */ + drm_gem_object_release(obj); + + kfree(meson_gem_obj); + meson_gem_obj = NULL; +} + +int am_meson_gem_object_mmap( + struct am_meson_gem_object *obj, + struct vm_area_struct *vma) +{ + int ret = 0; + struct ion_buffer *buffer; + + /* + * 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_flags &= ~VM_PFNMAP; + vma->vm_pgoff = 0; + + if (obj->sgt) { + DRM_ERROR("am_meson_gem_object_mmap imported buffer.\n"); + /*should NOT run to here.*/ + #if 0 + ret = dma_mmap_wc(obj->base.dev->dev, vma, + page_address(sg_page(obj->sgt->sgl)), + sg_dma_address(obj->sgt->sgl), + vma->vm_end - vma->vm_start); + #endif + } else { + buffer = obj->handle->buffer; + + if (!buffer->heap->ops->map_user) { + DRM_ERROR("%s:heap does not define map to userspace\n", + __func__); + ret = -EINVAL; + } else { + + if (!(buffer->flags & ION_FLAG_CACHED)) + vma->vm_page_prot = + pgprot_writecombine(vma->vm_page_prot); + + mutex_lock(&buffer->lock); + /* now map it to userspace */ + ret = buffer->heap->ops->map_user( + buffer->heap, buffer, vma); + mutex_unlock(&buffer->lock); + } + } + + if (ret) { + DRM_ERROR("%s: failure mapping buffer to userspace (%d)\n", + __func__, ret); + drm_gem_vm_close(vma); + } + + return ret; +} + +int am_meson_gem_mmap( + struct file *filp, + struct vm_area_struct *vma) +{ + struct drm_gem_object *obj; + struct am_meson_gem_object *meson_gem_obj; + int ret; + + ret = drm_gem_mmap(filp, vma); + if (ret) + return ret; + + obj = vma->vm_private_data; + meson_gem_obj = to_am_meson_gem_obj(obj); + DRM_ERROR("am_meson_gem_mmap %p.\n", meson_gem_obj); + + ret = am_meson_gem_object_mmap(meson_gem_obj, vma); + + return ret; +} + +int am_meson_gem_object_get_phyaddr( + struct meson_drm *drm, + struct am_meson_gem_object *meson_gem) +{ + int addr; + size_t len; + + ion_phys(drm->gem_client, meson_gem->handle, + (ion_phys_addr_t *)&addr, &len); + + return addr; +} + +int am_meson_gem_dumb_create( + struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + int ret = 0; + struct am_meson_gem_object *meson_gem_obj; + struct meson_drm *drmdrv = dev->dev_private; + struct ion_client *client = (struct ion_client *)drmdrv->gem_client; + int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + + args->pitch = ALIGN(min_pitch, 64); + if (args->size < args->pitch * args->height) + args->size = args->pitch * args->height; + + args->size = round_up(args->size, PAGE_SIZE); + + meson_gem_obj = am_meson_gem_object_create( + dev, args->flags, args->size, client); + if (IS_ERR(meson_gem_obj)) + return PTR_ERR(meson_gem_obj); + + /* + * allocate a id of idr table where the obj is registered + * and handle has the id what user can see. + */ + ret = drm_gem_handle_create(file_priv, + &meson_gem_obj->base, &args->handle); + /* drop reference from allocate - handle holds it now. */ + drm_gem_object_unreference_unlocked(&meson_gem_obj->base); + if (ret) { + DRM_ERROR("%s: create dumb handle failed %d\n", + __func__, ret); + return ret; + } + + DRM_DEBUG("%s: create dumb %p with gem handle (0x%x)\n", + __func__, meson_gem_obj, args->handle); + return 0; +} + +int am_meson_gem_dumb_destroy( + struct drm_file *file, + struct drm_device *dev, + uint32_t handle) +{ + DRM_DEBUG("%s: destroy dumb with handle (0x%x)\n", __func__, handle); + drm_gem_handle_delete(file, handle); + return 0; +} + +int am_meson_gem_dumb_map_offset( + struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle, + uint64_t *offset) +{ + struct drm_gem_object *obj; + int ret = 0; + + mutex_lock(&dev->struct_mutex); + + /* + * get offset of memory allocated for drm framebuffer. + * - this callback would be called by user application + * with DRM_IOCTL_MODE_MAP_DUMB command. + */ + obj = drm_gem_object_lookup(file_priv, handle); + if (!obj) { + DRM_ERROR("failed to lookup gem object.\n"); + ret = -EINVAL; + goto unlock; + } + + ret = drm_gem_create_mmap_offset(obj); + if (ret) + goto out; + + *offset = drm_vma_node_offset_addr(&obj->vma_node); + DRM_DEBUG("offset = 0x%lx\n", (unsigned long)*offset); + +out: + drm_gem_object_unreference(obj); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int am_meson_gem_create(struct meson_drm *drmdrv) +{ + drmdrv->gem_client = meson_ion_client_create(-1, "meson-gem"); + if (!drmdrv->gem_client) { + DRM_ERROR("open ion client error\n"); + return -EFAULT; + } + + DRM_DEBUG("open ion client: %p\n", drmdrv->gem_client); + return 0; +} + +void am_meson_gem_cleanup(struct meson_drm *drmdrv) +{ + struct ion_client *gem_ion_client = drmdrv->gem_client; + + if (gem_ion_client) { + DRM_DEBUG(" destroy ion client: %p\n", gem_ion_client); + ion_client_destroy(gem_ion_client); + } +} + +/* PRIME operations */ +struct dma_buf *am_meson_gem_prime_export( + struct drm_device *drm_dev, + struct drm_gem_object *obj, + int flags) +{ + struct am_meson_gem_object *meson_gem_obj; + struct ion_handle *handle; + + meson_gem_obj = to_am_meson_gem_obj(obj); + handle = meson_gem_obj->handle; + + if (!handle) + return ERR_PTR(-EINVAL); + + return ion_share_dma_buf(handle->client, handle); +} + +struct drm_gem_object *am_meson_gem_prime_import( + struct drm_device *drm_dev, + struct dma_buf *dma_buf) +{ + struct dma_buf_attachment *attach; + struct sg_table *sgt; + struct am_meson_gem_object *meson_gem_obj = NULL; + int ret; + + attach = dma_buf_attach(dma_buf, drm_dev->dev); + if (IS_ERR(attach)) + return ERR_PTR(-EINVAL); + + get_dma_buf(dma_buf); + + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(sgt)) { + ret = PTR_ERR(sgt); + goto err_buf_detach; + } + + meson_gem_obj = kzalloc(sizeof(*meson_gem_obj), GFP_KERNEL); + if (!meson_gem_obj) { + ret = -ENOMEM; + goto err_unmap_attach; + } + + ret = drm_gem_object_init(drm_dev, &meson_gem_obj->base, dma_buf->size); + if (ret < 0) { + DRM_ERROR("failed to initialize gem object\n"); + ret = -ENOMEM; + goto err_unmap_attach; + } + + meson_gem_obj->sgt = sgt; + meson_gem_obj->base.import_attach = attach; + + return &meson_gem_obj->base; + +err_unmap_attach: + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); +err_buf_detach: + dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + kfree(meson_gem_obj); + + return ERR_PTR(ret); +} + +#if 0 +struct sg_table *am_meson_gem_prime_get_sg_table(struct drm_gem_object *obj) +{ + struct am_meson_gem_object *meson_gem_obj; + struct sg_table *src_sgt; + struct sg_table *sgt; + int ret; + + meson_gem_obj = to_am_meson_gem_obj(obj); + DRM_DEBUG("am_meson_gem_prime_get_sg_table %p.\n", meson_gem_obj); + + if (meson_gem_obj->sgt) + src_sgt = meson_gem_obj->sgt; + else + src_sgt = meson_gem_obj->handle->buffer->sg_table; + + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) + return NULL; + + ret = dma_get_sgtable(obj->dev->dev, sgt, + page_address(sg_page(src_sgt->sgl)), + sg_dma_address(src_sgt->sgl), obj->size); + if (ret < 0) { + kfree(sgt); + return NULL; + } + + return sgt; +} + +struct drm_gem_object *am_meson_gem_prime_import_sg_table( + struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt) +{ + struct am_meson_gem_object *meson_gem_obj; + int ret; + + meson_gem_obj = kzalloc(sizeof(*meson_gem_obj), GFP_KERNEL); + if (!meson_gem_obj) + return ERR_PTR(-ENOMEM); + + ret = drm_gem_object_init(dev, + &meson_gem_obj->base, + attach->dmabuf->size); + if (ret < 0) { + DRM_ERROR("failed to initialize gem object\n"); + kfree(meson_gem_obj); + return ERR_PTR(-ENOMEM); + } + + DRM_DEBUG("%s: %p, sg_table %p\n", __func__, meson_gem_obj, sgt); + meson_gem_obj->sgt = sgt; + return &meson_gem_obj->base; +} + +void *am_meson_gem_prime_vmap(struct drm_gem_object *obj) +{ + struct am_meson_gem_object *meson_gem_obj; + + meson_gem_obj = to_am_meson_gem_obj(obj); + DRM_DEBUG("am_meson_gem_prime_vmap %p.\n", meson_gem_obj); + + return meson_gem_obj->handle->buffer->vaddr; +} + +void am_meson_gem_prime_vunmap( + struct drm_gem_object *obj, + void *vaddr) +{ + DRM_DEBUG("am_meson_gem_prime_vunmap nothing to do.\n"); +} + +int am_meson_gem_prime_mmap( + struct drm_gem_object *obj, + struct vm_area_struct *vma) +{ + struct am_meson_gem_object *meson_gem_obj; + int ret; + + ret = drm_gem_mmap_obj(obj, obj->size, vma); + if (ret < 0) + return ret; + + meson_gem_obj = to_am_meson_gem_obj(obj); + DRM_DEBUG("am_meson_gem_prime_mmap %p.\n", meson_gem_obj); + + return am_meson_gem_object_mmap(meson_gem_obj, vma); +} +#endif diff --git a/drivers/amlogic/drm/am_meson_gem.h b/drivers/amlogic/drm/am_meson_gem.h new file mode 100644 index 000000000000..ddfcbe0aedd8 --- /dev/null +++ b/drivers/amlogic/drm/am_meson_gem.h @@ -0,0 +1,79 @@ +/* + * drivers/amlogic/drm/am_meson_gem.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef __AM_MESON_GEM_H +#define __AM_MESON_GEM_H +#include +#include +#include "meson_drv.h" + +struct am_meson_gem_object { + struct drm_gem_object base; + unsigned int flags; + + /*for buffer create from ion heap */ + struct ion_handle *handle; + bool bscatter; + /*for buffer imported. */ + struct sg_table *sgt; + +}; + +/* GEM MANAGER CREATE*/ +int am_meson_gem_create(struct meson_drm *drmdrv); + +void am_meson_gem_cleanup(struct meson_drm *drmdrv); + +int am_meson_gem_mmap( + struct file *filp, + struct vm_area_struct *vma); + +/* GEM DUMB OPERATIONS */ +int am_meson_gem_dumb_create( + struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args); + +int am_meson_gem_dumb_destroy( + struct drm_file *file, + struct drm_device *dev, + uint32_t handle); + +int am_meson_gem_dumb_map_offset( + struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle, + uint64_t *offset); + +/* GEM OBJECT OPERATIONS */ +void am_meson_gem_object_free(struct drm_gem_object *gem_obj); + +int am_meson_gem_object_get_phyaddr( + struct meson_drm *drm, + struct am_meson_gem_object *meson_gem); + +/* GEM PRIME OPERATIONS */ +struct drm_gem_object *am_meson_gem_prime_import( + struct drm_device *drm_dev, + struct dma_buf *dma_buf); + +struct dma_buf *am_meson_gem_prime_export( + struct drm_device *drm_dev, + struct drm_gem_object *obj, + int flags); + +#endif /* __AM_MESON_GEM_H */ diff --git a/drivers/amlogic/drm/am_meson_hdmi.c b/drivers/amlogic/drm/am_meson_hdmi.c new file mode 100644 index 000000000000..d5419593a361 --- /dev/null +++ b/drivers/amlogic/drm/am_meson_hdmi.c @@ -0,0 +1,165 @@ +/* + * drivers/amlogic/drm/am_meson_hdmi.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include +#include +#include +#include +#include + +#include "am_meson_hdmi.h" + +struct drm_display_mode am_hdmi_modes[] = { + /* 1280x720@60Hz */ + { DRM_MODE("720p60hz", DRM_MODE_TYPE_DRIVER | + DRM_MODE_TYPE_PREFERRED, 74250, 1280, 1390, + 1430, 1650, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9,}, + + /* 1280x720@50Hz */ + { DRM_MODE("720p50hz", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, + 1760, 1980, 0, 720, 725, 730, 750, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + + /* 1920x1080@60Hz */ + { DRM_MODE("1080p60hz", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, + 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + + /* 1920x1080@50Hz */ + { DRM_MODE("1080p50hz", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, + 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + + /* 3840x2160@30Hz */ + { DRM_MODE("2160p30hz", DRM_MODE_TYPE_DRIVER, 297000, + 3840, 4016, 4104, 4400, 0, + 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, }, +}; + +int am_hdmi_tx_get_modes(struct drm_connector *connector) +{ + int count; + struct drm_display_mode *mode; + + for (count = 0; count < ARRAY_SIZE(am_hdmi_modes); count++) { + mode = drm_mode_duplicate(connector->dev, + &am_hdmi_modes[count]); + drm_mode_probed_add(connector, mode); + } + return count; +} + +enum drm_mode_status am_hdmi_tx_check_mode(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + + +static const +struct drm_connector_helper_funcs am_hdmi_connector_helper_funcs = { + .get_modes = am_hdmi_tx_get_modes, + .mode_valid = am_hdmi_tx_check_mode, +}; + +static enum drm_connector_status +am_hdmi_connector_detect(struct drm_connector *connector, bool force) +{ + /* FIXME: Add load-detect or jack-detect if possible */ + return connector_status_connected; +} + +static const struct drm_connector_funcs am_hdmi_connector_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .detect = am_hdmi_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static void am_hdmi_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + //DRM_DEBUG("am_hdmi_encoder_mode_set "); +} + +static const struct drm_encoder_helper_funcs + am_hdmi_encoder_helper_funcs = { + .mode_set = am_hdmi_encoder_mode_set, +}; + +static const struct drm_encoder_funcs am_hdmi_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + + +int am_hdmi_connector_create(struct meson_drm *priv) +{ + struct drm_device *drm = priv->drm; + struct am_hdmi_tx *am_hdmi; + struct drm_connector *connector; + struct drm_encoder *encoder; + int ret; + + am_hdmi = devm_kzalloc(priv->dev, sizeof(*am_hdmi), + GFP_KERNEL); + if (!am_hdmi) + return -ENOMEM; + + am_hdmi->priv = priv; + + encoder = &am_hdmi->encoder; + connector = &am_hdmi->connector; + + /* Connector */ + drm_connector_helper_add(connector, + &am_hdmi_connector_helper_funcs); + + ret = drm_connector_init(drm, connector, &am_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + if (ret) { + dev_err(priv->dev, "Failed to init hdmi tx connector\n"); + return ret; + } + + connector->interlace_allowed = 1; + + /* Encoder */ + drm_encoder_helper_add(encoder, &am_hdmi_encoder_helper_funcs); + + ret = drm_encoder_init(drm, encoder, &am_hdmi_encoder_funcs, + DRM_MODE_ENCODER_TVDAC, "am_hdmi_encoder"); + if (ret) { + dev_err(priv->dev, "Failed to init hdmi encoder\n"); + return ret; + } + + encoder->possible_crtcs = BIT(0); + + drm_mode_connector_attach_encoder(connector, encoder); + return 0; +} + diff --git a/drivers/amlogic/drm/meson_dmabuf.h b/drivers/amlogic/drm/am_meson_hdmi.h similarity index 62% rename from drivers/amlogic/drm/meson_dmabuf.h rename to drivers/amlogic/drm/am_meson_hdmi.h index 3afcf0b1ee2d..6c0fd520cc62 100644 --- a/drivers/amlogic/drm/meson_dmabuf.h +++ b/drivers/amlogic/drm/am_meson_hdmi.h @@ -1,5 +1,5 @@ /* - * drivers/amlogic/drm/meson_dmabuf.h + * drivers/amlogic/drm/am_meson_hdmi.h * * Copyright (C) 2017 Amlogic, Inc. All rights reserved. * @@ -14,14 +14,18 @@ * more details. * */ +#ifndef __AM_MESON_HDMI_H +#define __AM_MESON_HDMI_H -#ifndef _MESON_DRM_DMABUF_H_ -#define _MESON_DRM_DMABUF_H_ +#include "meson_drv.h" -struct dma_buf *meson_dmabuf_prime_export(struct drm_device *drm_dev, - struct drm_gem_object *obj, int flags); +struct am_hdmi_tx { + struct drm_encoder encoder; + struct drm_connector connector; + struct meson_drm *priv; +}; -struct drm_gem_object *meson_dmabuf_prime_import(struct drm_device *drm_dev, - struct dma_buf *dma_buf); +int am_hdmi_connector_create(struct meson_drm *priv); + +#endif -#endif /* MESON_DRM_DMABUF_H */ diff --git a/drivers/amlogic/drm/am_meson_plane.c b/drivers/amlogic/drm/am_meson_plane.c new file mode 100644 index 000000000000..4996d6b7597b --- /dev/null +++ b/drivers/amlogic/drm/am_meson_plane.c @@ -0,0 +1,258 @@ +/* + * drivers/amlogic/drm/am_meson_plane.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "osd.h" +#include "osd_drm.h" + +#include "meson_plane.h" +#ifdef CONFIG_DRM_MESON_USE_ION +#include "am_meson_fb.h" +#endif + +#define to_am_osd_plane(x) container_of(x, struct am_osd_plane, base) + +struct am_osd_plane { + struct drm_plane base; //must be first element. + struct meson_drm *drv; //point to struct parent. + struct dentry *plane_debugfs_dir; + + u32 osd_idx; +}; + +static const struct drm_plane_funcs am_osd_plane_funs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +int am_osd_begin_display( + struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct am_osd_plane *osd_plane = to_am_osd_plane(plane); + + DRM_DEBUG("%s osd %d.\n", __func__, osd_plane->osd_idx); + return 0; +} + +void am_osd_end_display( + struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct am_osd_plane *osd_plane = to_am_osd_plane(plane); + + DRM_DEBUG("%s osd %d.\n", __func__, osd_plane->osd_idx); +} + +void am_osd_do_display( + struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct am_osd_plane *osd_plane = to_am_osd_plane(plane); + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + struct meson_drm *drv = osd_plane->drv; + struct osd_plane_map_s plane_map; +#ifdef CONFIG_DRM_MESON_USE_ION + struct am_meson_fb *meson_fb; +#else + struct drm_gem_cma_object *gem; +#endif + int format = DRM_FORMAT_ARGB8888; + dma_addr_t phyaddr; + unsigned long flags; + + //DRM_INFO("am_osd_do_display osd %d.\n", osd_plane->osd_idx); + + switch (fb->pixel_format) { + case DRM_FORMAT_XRGB8888: + format = COLOR_INDEX_32_XRGB; + break; + case DRM_FORMAT_XBGR8888: + format = COLOR_INDEX_32_XBGR; + break; + case DRM_FORMAT_RGBX8888: + format = COLOR_INDEX_32_RGBX; + break; + case DRM_FORMAT_BGRX8888: + format = COLOR_INDEX_32_BGRX; + break; + case DRM_FORMAT_ARGB8888: + format = COLOR_INDEX_32_ARGB; + break; + case DRM_FORMAT_ABGR8888: + format = COLOR_INDEX_32_ABGR; + break; + case DRM_FORMAT_RGBA8888: + format = COLOR_INDEX_32_RGBA; + break; + case DRM_FORMAT_BGRA8888: + format = COLOR_INDEX_32_BGRA; + break; + case DRM_FORMAT_RGB888: + format = COLOR_INDEX_24_RGB; + break; + case DRM_FORMAT_RGB565: + format = COLOR_INDEX_16_565; + break; + case DRM_FORMAT_ARGB1555: + format = COLOR_INDEX_16_1555_A; + break; + case DRM_FORMAT_ARGB4444: + format = COLOR_INDEX_16_4444_A; + break; + default: + DRM_INFO("unsupport fb->pixel_format=%x\n", fb->pixel_format); + break; + }; + + spin_lock_irqsave(&drv->drm->event_lock, flags); + +#ifdef CONFIG_DRM_MESON_USE_ION + meson_fb = container_of(fb, struct am_meson_fb, base); + phyaddr = am_meson_gem_object_get_phyaddr(drv, meson_fb->bufp); + if (meson_fb->bufp->bscatter) + DRM_ERROR("ERROR:am_meson_plane meet a scatter framebuffe.\nr"); +#else + /* Update Canvas with buffer address */ + gem = drm_fb_cma_get_gem_obj(fb, 0); + phyaddr = gem->paddr; +#endif + + /* setup osd display parameters */ + plane_map.plane_index = osd_plane->osd_idx; + plane_map.zorder = state->zpos; + plane_map.phy_addr = phyaddr; + plane_map.enable = 1; + plane_map.format = format; + plane_map.byte_stride = fb->pitches[0]; + + plane_map.src_x = state->src_x; + plane_map.src_y = state->src_y; + plane_map.src_w = (state->src_w >> 16) & 0xffff; + plane_map.src_h = (state->src_h >> 16) & 0xffff; + + plane_map.dst_x = state->crtc_x; + plane_map.dst_y = state->crtc_y; + plane_map.dst_w = state->crtc_w; + plane_map.dst_h = state->crtc_h; + #if 0 + DRM_INFO("flags:%d pixel_format:%d,zpos=%d\n", + fb->flags, fb->pixel_format, state->zpos); + DRM_INFO("plane index=%d, type=%d\n", plane->index, plane->type); + #endif + osd_drm_plane_page_flip(&plane_map); + + spin_unlock_irqrestore(&drv->drm->event_lock, flags); +} + +int am_osd_check(struct drm_plane *plane, struct drm_plane_state *state) +{ + struct am_osd_plane *osd_plane = to_am_osd_plane(plane); + + DRM_DEBUG("am_osd_check osd %d.\n", osd_plane->osd_idx); + return 0; +} + +void am_osd_blank(struct drm_plane *plane, struct drm_plane_state *old_state) +{ + struct am_osd_plane *osd_plane = to_am_osd_plane(plane); + + DRM_DEBUG("am_osd_blank osd %d.\n", osd_plane->osd_idx); +} + +static const struct drm_plane_helper_funcs am_osd_helper_funcs = { + .prepare_fb = am_osd_begin_display, + .cleanup_fb = am_osd_end_display, + .atomic_update = am_osd_do_display, + .atomic_check = am_osd_check, + .atomic_disable = am_osd_blank, +}; + +static const uint32_t supported_drm_formats[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, +}; + +struct am_osd_plane *am_osd_plane_create(struct meson_drm *priv, u32 type) +{ + struct am_osd_plane *osd_plane; + struct drm_plane *plane; + char *plane_name = NULL; + + osd_plane = devm_kzalloc(priv->drm->dev, sizeof(*osd_plane), + GFP_KERNEL); + if (!osd_plane) + return 0; + + osd_plane->drv = priv; + plane = &osd_plane->base; + + if (type == DRM_PLANE_TYPE_PRIMARY) { + osd_plane->osd_idx = 0; + plane_name = "osd-0"; + } else if (type == DRM_PLANE_TYPE_CURSOR) { + osd_plane->osd_idx = 1; + plane_name = "osd-1"; + } + + drm_universal_plane_init(priv->drm, plane, 0xFF, + &am_osd_plane_funs, + supported_drm_formats, + ARRAY_SIZE(supported_drm_formats), + type, plane_name); + + drm_plane_helper_add(plane, &am_osd_helper_funcs); + osd_drm_debugfs_add(&(osd_plane->plane_debugfs_dir), + plane_name, osd_plane->osd_idx); + return osd_plane; +} + +int meson_plane_create(struct meson_drm *priv) +{ + struct am_osd_plane *plane; + + DRM_DEBUG("amlogic meson_plane_create. enter\n"); + /*crate primary plane*/ + plane = am_osd_plane_create(priv, DRM_PLANE_TYPE_PRIMARY); + if (plane == NULL) + return -ENOMEM; + + priv->primary_plane = &(plane->base); + + /*crate cursor plane*/ + plane = am_osd_plane_create(priv, DRM_PLANE_TYPE_CURSOR); + if (plane == NULL) + return -ENOMEM; + + priv->cursor_plane = &(plane->base); + + return 0; +} + diff --git a/drivers/amlogic/drm/meson_dmabuf.c b/drivers/amlogic/drm/meson_dmabuf.c deleted file mode 100644 index aba629d61214..000000000000 --- a/drivers/amlogic/drm/meson_dmabuf.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * drivers/amlogic/drm/meson_dmabuf.c - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#include -#include -#include - -#include "meson_gem.h" -#include "meson_dmabuf.h" - -struct dma_buf *meson_dmabuf_prime_export(struct drm_device *drm_dev, - struct drm_gem_object *obj, int flags) -{ - struct meson_gem_object *meson_gem_obj; - struct ion_handle *handle; - - meson_gem_obj = container_of(obj, struct meson_gem_object, base); - handle = meson_gem_obj->handle; - - if (!handle) - return ERR_PTR(-EINVAL); - - return ion_share_dma_buf(handle->client, handle); -} - -struct drm_gem_object *meson_dmabuf_prime_import(struct drm_device *drm_dev, - struct dma_buf *dma_buf) -{ - struct dma_buf_attachment *attach; - struct sg_table *sgt; - struct meson_gem_object *meson_gem_obj; - int ret; - - attach = dma_buf_attach(dma_buf, drm_dev->dev); - if (IS_ERR(attach)) - return ERR_PTR(-EINVAL); - - get_dma_buf(dma_buf); - - sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); - if (IS_ERR_OR_NULL(sgt)) { - ret = PTR_ERR(sgt); - goto err_buf_detach; - } - - meson_gem_obj = meson_drm_gem_init(drm_dev, dma_buf->size); - if (!meson_gem_obj) { - ret = -ENOMEM; - goto err_unmap_attach; - } - - meson_gem_obj->sgt = sgt; - meson_gem_obj->base.import_attach = attach; - - return &meson_gem_obj->base; - -err_unmap_attach: - dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); -err_buf_detach: - dma_buf_detach(dma_buf, attach); - dma_buf_put(dma_buf); - - return ERR_PTR(ret); -} diff --git a/drivers/amlogic/drm/meson_drv.c b/drivers/amlogic/drm/meson_drv.c index b8e58dba63e2..dde7ac8acc3d 100644 --- a/drivers/amlogic/drm/meson_drv.c +++ b/drivers/amlogic/drm/meson_drv.c @@ -27,16 +27,11 @@ #include #include - -/* #define MUSE */ -#ifdef MUSE #include #include #include #include #include -#endif - #include #include #include @@ -46,14 +41,20 @@ #include "meson_plane.h" #include "meson_crtc.h" #include "meson_venc_cvbs.h" - +#ifdef CONFIG_DRM_MESON_BYPASS_MODE +#include "am_meson_hdmi.h" +#include "osd_drm.h" +#else #include "meson_vpp.h" #include "meson_viu.h" #include "meson_venc.h" #include "meson_canvas.h" #include "meson_registers.h" -#include "meson_gem.h" -#include "meson_dmabuf.h" +#endif +#ifdef CONFIG_DRM_MESON_USE_ION +#include "am_meson_gem.h" +#include "am_meson_fb.h" +#endif #define DRIVER_NAME "meson" #define DRIVER_DESC "Amlogic Meson DRM driver" @@ -71,35 +72,42 @@ * - Powering up video processing HW blocks * - Powering Up HDMI controller and PHY */ - -#ifdef MUSE static void meson_fb_output_poll_changed(struct drm_device *dev) { +#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV struct meson_drm *priv = dev->dev_private; - drm_fbdev_cma_hotplug_event(priv->fbdev); +#endif } + static const struct drm_mode_config_funcs meson_mode_config_funcs = { .output_poll_changed = meson_fb_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, +#ifdef CONFIG_DRM_MESON_USE_ION + .fb_create = am_meson_fb_create, +#else .fb_create = drm_fb_cma_create, +#endif }; static int meson_enable_vblank(struct drm_device *dev, unsigned int crtc) { +#ifndef CONFIG_DRM_MESON_BYPASS_MODE struct meson_drm *priv = dev->dev_private; meson_venc_enable_vsync(priv); - +#endif return 0; } static void meson_disable_vblank(struct drm_device *dev, unsigned int crtc) { +#ifndef CONFIG_DRM_MESON_BYPASS_MODE struct meson_drm *priv = dev->dev_private; meson_venc_disable_vsync(priv); +#endif } static irqreturn_t meson_irq(int irq, void *arg) @@ -107,13 +115,14 @@ static irqreturn_t meson_irq(int irq, void *arg) struct drm_device *dev = arg; struct meson_drm *priv = dev->dev_private; +#ifndef CONFIG_DRM_MESON_BYPASS_MODE (void)readl_relaxed(priv->io_base + _REG(VENC_INTFLAG)); +#endif meson_crtc_irq(priv); return IRQ_HANDLED; } -#endif static const struct file_operations fops = { .owner = THIS_MODULE, @@ -126,16 +135,18 @@ static const struct file_operations fops = { .poll = drm_poll, .read = drm_read, .llseek = no_llseek, +#ifdef CONFIG_DRM_MESON_USE_ION + .mmap = am_meson_gem_mmap, +#else .mmap = drm_gem_cma_mmap, +#endif }; static struct drm_driver meson_driver = { - .driver_features = DRIVER_GEM | DRIVER_PRIME, -#ifdef MUSE .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | - DRIVER_ATOMIC, + DRIVER_ATOMIC | DRIVER_IRQ_SHARED, /* Vblank */ .enable_vblank = meson_enable_vblank, @@ -144,22 +155,40 @@ static struct drm_driver meson_driver = { /* IRQ */ .irq_handler = meson_irq, -#endif +#ifdef CONFIG_DRM_MESON_USE_ION /* PRIME Ops */ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import = meson_dmabuf_prime_import, - .gem_prime_export = meson_dmabuf_prime_export, + .gem_prime_import = am_meson_gem_prime_import, + .gem_prime_export = am_meson_gem_prime_export, /* GEM Ops */ - .open = meson_drm_gem_open, - .postclose = meson_drm_gem_close, - .dumb_create = meson_drm_gem_dumb_create, - .dumb_destroy = meson_drm_gem_dumb_destroy, - .dumb_map_offset = meson_drm_gem_dumb_map_offset, - .gem_free_object = meson_drm_gem_free_object, + .dumb_create = am_meson_gem_dumb_create, + .dumb_destroy = am_meson_gem_dumb_destroy, + .dumb_map_offset = am_meson_gem_dumb_map_offset, + + .gem_free_object_unlocked = am_meson_gem_object_free, .gem_vm_ops = &drm_gem_cma_vm_ops, +#else + /* PRIME Ops */ + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + + /* GEM Ops */ + .dumb_create = drm_gem_cma_dumb_create, + .dumb_destroy = drm_gem_dumb_destroy, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, +#endif /* Misc */ .fops = &fops, @@ -170,7 +199,7 @@ static struct drm_driver meson_driver = { .minor = 0, }; -#ifdef MUSE +#ifndef CONFIG_DRM_MESON_BYPASS_MODE static bool meson_vpu_has_available_connectors(struct device *dev) { struct device_node *ep, *remote; @@ -201,7 +230,7 @@ static int meson_drv_probe(struct platform_device *pdev) struct drm_device *drm; int ret; -#ifdef MUSE +#ifndef CONFIG_DRM_MESON_BYPASS_MODE struct resource *res; void __iomem *regs; @@ -225,7 +254,7 @@ static int meson_drv_probe(struct platform_device *pdev) priv->drm = drm; priv->dev = dev; -#ifdef MUSE +#ifndef CONFIG_DRM_MESON_BYPASS_MODE res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) @@ -258,14 +287,20 @@ static int meson_drv_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); return PTR_ERR(priv->dmc); } +#endif + +#ifdef CONFIG_DRM_MESON_USE_ION + am_meson_gem_create(priv); +#endif priv->vsync_irq = platform_get_irq(pdev, 0); - drm_vblank_init(drm, 1); drm_mode_config_init(drm); +#ifdef CONFIG_DRM_MESON_BYPASS_MODE + am_hdmi_connector_create(priv); +#else /* Encoder Initialization */ - ret = meson_venc_cvbs_create(priv); if (ret) goto free_drm; @@ -275,6 +310,7 @@ static int meson_drv_probe(struct platform_device *pdev) meson_venc_init(priv); meson_vpp_init(priv); meson_viu_init(priv); +#endif ret = meson_plane_create(priv); if (ret) @@ -293,6 +329,7 @@ static int meson_drv_probe(struct platform_device *pdev) drm->mode_config.max_height = 8192; drm->mode_config.funcs = &meson_mode_config_funcs; +#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc, drm->mode_config.num_connector); @@ -300,9 +337,9 @@ static int meson_drv_probe(struct platform_device *pdev) ret = PTR_ERR(priv->fbdev); goto free_drm; } +#endif drm_kms_helper_poll_init(drm); -#endif platform_set_drvdata(pdev, priv); @@ -310,14 +347,15 @@ static int meson_drv_probe(struct platform_device *pdev) if (ret) goto free_drm; +#ifdef CONFIG_DRM_MESON_BYPASS_MODE + osd_drm_debugfs_init(); +#endif + return 0; free_drm: DRM_DEBUG("free-drm"); - -#ifdef MUSE drm_dev_unref(drm); -#endif return ret; } @@ -325,18 +363,22 @@ free_drm: static int meson_drv_remove(struct platform_device *pdev) { struct drm_device *drm = dev_get_drvdata(&pdev->dev); -#ifdef MUSE struct meson_drm *priv = drm->dev_private; -#endif +#ifdef CONFIG_DRM_MESON_BYPASS_MODE + osd_drm_debugfs_exit(); +#endif drm_dev_unregister(drm); -#ifdef MUSE drm_kms_helper_poll_fini(drm); +#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV drm_fbdev_cma_fini(priv->fbdev); +#endif drm_mode_config_cleanup(drm); drm_vblank_cleanup(drm); - drm_dev_unref(drm); +#ifdef CONFIG_DRM_MESON_USE_ION + am_meson_gem_cleanup(priv); #endif + drm_dev_unref(drm); return 0; } @@ -363,5 +405,6 @@ module_platform_driver(meson_drm_platform_driver); MODULE_AUTHOR("Jasper St. Pierre "); MODULE_AUTHOR("Neil Armstrong "); +MODULE_AUTHOR("MultiMedia Amlogic "); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/amlogic/drm/meson_drv.h b/drivers/amlogic/drm/meson_drv.h index 6195327c51ca..61375f9c5014 100644 --- a/drivers/amlogic/drm/meson_drv.h +++ b/drivers/amlogic/drm/meson_drv.h @@ -23,19 +23,28 @@ #include #include #include +#ifdef CONFIG_DRM_MESON_USE_ION +#include +#endif struct meson_drm { struct device *dev; + +#ifndef CONFIG_DRM_MESON_BYPASS_MODE void __iomem *io_base; struct regmap *hhi; struct regmap *dmc; +#endif + int vsync_irq; struct drm_device *drm; struct drm_crtc *crtc; struct drm_fbdev_cma *fbdev; struct drm_plane *primary_plane; + struct drm_plane *cursor_plane; +#ifndef CONFIG_DRM_MESON_BYPASS_MODE /* Components Data */ struct { bool osd1_enabled; @@ -48,6 +57,11 @@ struct meson_drm { struct { unsigned int current_mode; } venc; +#endif + +#ifdef CONFIG_DRM_MESON_USE_ION + struct ion_client *gem_client; +#endif }; static inline int meson_vpu_is_compatible(struct meson_drm *priv, diff --git a/drivers/amlogic/drm/meson_gem.c b/drivers/amlogic/drm/meson_gem.c deleted file mode 100644 index 28d68f082a81..000000000000 --- a/drivers/amlogic/drm/meson_gem.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * drivers/amlogic/drm/meson_gem.c - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include "meson_drv.h" -#include "meson_gem.h" - - -struct meson_gem_object *meson_drm_gem_init(struct drm_device *dev, - unsigned long size) -{ - struct meson_gem_object *meson_gem_obj; - struct drm_gem_object *obj; - int ret; - - meson_gem_obj = kzalloc(sizeof(*meson_gem_obj), GFP_KERNEL); - if (!meson_gem_obj) - return NULL; - - meson_gem_obj->size = size; - obj = &meson_gem_obj->base; - - ret = drm_gem_object_init(dev, obj, size); - if (ret < 0) { - DRM_ERROR("failed to initialize gem object\n"); - kfree(meson_gem_obj); - return NULL; - } - - DRM_DEBUG("created file object = 0x%lx\n", (unsigned long)obj->filp); - - return meson_gem_obj; -} - -static int meson_drm_alloc_buf(struct ion_client *client, - struct meson_gem_object *meson_gem_obj, int flags) -{ - if (!client) - return -EINVAL; - - if (!meson_gem_obj) - return -EINVAL; - - meson_gem_obj->handle = ion_alloc(client, - meson_gem_obj->size, - 0, - (1 << ION_HEAP_TYPE_SYSTEM), - 0); - - if (!meson_gem_obj->handle) - return -ENOMEM; - - return 0; -} - -static struct meson_gem_object *meson_drm_gem_create(struct drm_device *dev, - unsigned int flags, - unsigned long size, - struct ion_client *client) -{ - struct meson_gem_object *meson_gem_obj; - int ret; - - if (!size) { - DRM_ERROR("invalid size.\n"); - return ERR_PTR(-EINVAL); - } - - size = round_up(size, PAGE_SIZE); - meson_gem_obj = meson_drm_gem_init(dev, size); - if (!meson_gem_obj) { - ret = -ENOMEM; - return ERR_PTR(ret); - } - - ret = meson_drm_alloc_buf(client, meson_gem_obj, flags); - if (ret < 0) - goto err_gem_fini; - - return meson_gem_obj; - -err_gem_fini: - drm_gem_object_release(&meson_gem_obj->base); - kfree(meson_gem_obj); - return ERR_PTR(ret); -} - -static int meson_drm_gem_handle_create(struct drm_gem_object *obj, - struct drm_file *file_priv, - unsigned int *handle) -{ - int ret; - - /* - * allocate a id of idr table where the obj is registered - * and handle has the id what user can see. - */ - ret = drm_gem_handle_create(file_priv, obj, handle); - if (ret) - return ret; - - DRM_DEBUG("gem handle = 0x%x\n", *handle); - - /* drop reference from allocate - handle holds it now. */ - drm_gem_object_unreference_unlocked(obj); - - return 0; -} - -static void meson_drm_free_buf(struct drm_device *dev, - struct meson_gem_object *meson_gem_obj) -{ - struct ion_client *client = NULL; - - if (meson_gem_obj->handle) { - client = meson_gem_obj->handle->client; - ion_free(client, meson_gem_obj->handle); - } else { - DRM_ERROR("meson_gem_obj handle is null\n"); - } -} - -void meson_drm_gem_destroy(struct meson_gem_object *meson_gem_obj) -{ - struct drm_gem_object *obj; - - obj = &meson_gem_obj->base; - - DRM_DEBUG("handle count = %d\n", obj->handle_count); - - /* - * do not release memory region from exporter. - * - * the region will be released by exporter - * once dmabuf's refcount becomes 0. - */ - if (obj->import_attach) - goto out; - - meson_drm_free_buf(obj->dev, meson_gem_obj); - -out: - - drm_gem_free_mmap_offset(obj); - - /* release file pointer to gem object. */ - drm_gem_object_release(obj); - - kfree(meson_gem_obj); - meson_gem_obj = NULL; -} - -int meson_drm_gem_dumb_create(struct drm_file *file_priv, - struct drm_device *dev, struct drm_mode_create_dumb *args) -{ - int ret = 0; - struct meson_gem_object *meson_gem_obj; - struct drm_meson_file_private *f = file_priv->driver_priv; - - struct ion_client *client = (struct ion_client *) f->client; - int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - - args->pitch = ALIGN(min_pitch, 64); - if (args->size < args->pitch * args->height) - args->size = args->pitch * args->height; - - meson_gem_obj = meson_drm_gem_create(dev, 0, args->size, client); - - if (IS_ERR(meson_gem_obj)) - return PTR_ERR(meson_gem_obj); - - ret = meson_drm_gem_handle_create(&meson_gem_obj->base, file_priv, - &args->handle); - if (ret) { - meson_drm_gem_destroy(meson_gem_obj); - return ret; - } - - return 0; -} - -int meson_drm_gem_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset) -{ - struct drm_gem_object *obj; - int ret = 0; - - mutex_lock(&dev->struct_mutex); - - /* - * get offset of memory allocated for drm framebuffer. - * - this callback would be called by user application - * with DRM_IOCTL_MODE_MAP_DUMB command. - */ - - obj = drm_gem_object_lookup(file_priv, handle); - if (!obj) { - DRM_ERROR("failed to lookup gem object.\n"); - ret = -EINVAL; - goto unlock; - } - - ret = drm_gem_create_mmap_offset(obj); - if (ret) - goto out; - - *offset = drm_vma_node_offset_addr(&obj->vma_node); - DRM_DEBUG("offset = 0x%lx\n", (unsigned long)*offset); - -out: - drm_gem_object_unreference(obj); -unlock: - mutex_unlock(&dev->struct_mutex); - return ret; -} - -void meson_drm_gem_free_object(struct drm_gem_object *obj) -{ - struct meson_gem_object *meson_gem_obj; - - meson_gem_obj = container_of(obj, struct meson_gem_object, base); - - if (obj->import_attach) - drm_prime_gem_destroy(obj, meson_gem_obj->sgt); - - meson_drm_gem_destroy(meson_gem_obj); -} - -int meson_drm_gem_dumb_destroy(struct drm_file *file, - struct drm_device *dev, - uint32_t handle) -{ - struct drm_gem_object *obj; - - spin_lock(&file->table_lock); - obj = idr_find(&file->object_idr, handle); - if (obj == NULL) { - spin_unlock(&file->table_lock); - return -EINVAL; - } - spin_unlock(&file->table_lock); - - drm_gem_handle_delete(file, handle); - - /* - * we still have a reference to dma_buf because the ion_handle, - * when gem obj handle count become zero and refcount is 1. - * It will not release when dma_buf_ops.release is called. - * we have to drop it here. - * drop the reference on the export fd holds - */ - - if (obj->handle_count == 0 && - atomic_read(&obj->refcount.refcount) == 1) - drm_gem_object_unreference_unlocked(obj); - - return 0; -} - -int meson_drm_gem_open(struct drm_device *dev, struct drm_file *file) -{ - struct drm_meson_file_private *file_priv; - - file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); - if (!file_priv) { - DRM_ERROR("drm_meson file private alloc fail\n"); - return -ENOMEM; - } - - file_priv->client = meson_ion_client_create(-1, "meson-gem"); - if (!file_priv->client) { - DRM_ERROR("open ion client error\n"); - return -EFAULT; - } - - DRM_DEBUG("open ion client: %p\n", file_priv->client); - file->driver_priv = (void *) file_priv; - return 0; -} - -void meson_drm_gem_close(struct drm_device *dev, struct drm_file *file) -{ - struct drm_meson_file_private *file_priv = file->driver_priv; - struct ion_client *gem_ion_client = file_priv->client; - - if (gem_ion_client) { - DRM_DEBUG(" destroy ion client: %p\n", gem_ion_client); - ion_client_destroy(gem_ion_client); - } -} diff --git a/drivers/amlogic/drm/meson_gem.h b/drivers/amlogic/drm/meson_gem.h deleted file mode 100644 index 3766ae96c16f..000000000000 --- a/drivers/amlogic/drm/meson_gem.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * drivers/amlogic/drm/meson_gem.h - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#ifndef __MESON_GEM_H -#define __MESON_GEM_H -#include -#include - -struct drm_meson_file_private { - struct ion_client *client; -}; - -struct meson_gem_object { - struct drm_gem_object base; - struct ion_handle *handle; - struct sg_table *sgt; - unsigned long size; - unsigned int flags; -}; - -/* create memory region for drm */ -int meson_drm_gem_dumb_create(struct drm_file *file_priv, - struct drm_device *dev, - struct drm_mode_create_dumb *args); - -/* map memory region for drm to user space. */ -int meson_drm_gem_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset); - -/* free gem object. */ -void meson_drm_gem_free_object(struct drm_gem_object *gem_obj); - -struct meson_gem_object *meson_drm_gem_init(struct drm_device *dev, - unsigned long size); - -int meson_drm_gem_dumb_destroy(struct drm_file *file, - struct drm_device *dev, - uint32_t handle); - -int meson_drm_gem_open(struct drm_device *dev, struct drm_file *file); -void meson_drm_gem_close(struct drm_device *dev, struct drm_file *file); - -#endif /* __MESON_GEM_H */ diff --git a/drivers/amlogic/media/osd/Makefile b/drivers/amlogic/media/osd/Makefile index 1153b169fe44..5800967b0b0a 100644 --- a/drivers/amlogic/media/osd/Makefile +++ b/drivers/amlogic/media/osd/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_AMLOGIC_MEDIA_FB) += fb.o fb-objs = osd_hw.o osd_fb.o osd_debug.o osd_backup.o osd_logo.o osd_io.o fb-objs += osd_antiflicker.o osd_clone.o - +fb-objs += osd_drm.o obj-$(CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA) += osd_rdma.o obj-$(CONFIG_INSTABOOT) += osd_progressbar.o diff --git a/drivers/amlogic/media/osd/osd.h b/drivers/amlogic/media/osd/osd.h index 3004ddfcd791..d4c3107ec4e6 100644 --- a/drivers/amlogic/media/osd/osd.h +++ b/drivers/amlogic/media/osd/osd.h @@ -365,8 +365,11 @@ struct hw_para_s { u32 screen_size[HW_OSD_COUNT]; char __iomem *screen_base_backup[HW_OSD_COUNT]; u32 screen_size_backup[HW_OSD_COUNT]; + u32 osd_clear[HW_OSD_COUNT]; u32 vinfo_width; u32 vinfo_height; + u32 fb_drvier_probe; }; + #endif /* _OSD_H_ */ diff --git a/drivers/amlogic/media/osd/osd_drm.c b/drivers/amlogic/media/osd/osd_drm.c new file mode 100644 index 000000000000..448dd3f326dc --- /dev/null +++ b/drivers/amlogic/media/osd/osd_drm.c @@ -0,0 +1,640 @@ +/* + * drivers/amlogic/media/osd/osd_hw.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Android Headers */ +#include +#include "osd_drm.h" +#include "osd_hw.h" +#include "osd.h" +#include "osd_log.h" + +#define MAX_PLANE 4 +static struct dentry *osd_debugfs_root; +static unsigned int osd_enable[MAX_PLANE]; +static int plane_osd_id[MAX_PLANE]; + +static int parse_para(const char *para, int para_num, int *result) +{ + char *token = NULL; + char *params, *params_base; + int *out = result; + int len = 0, count = 0; + int res = 0; + int ret = 0; + + if (!para) + return 0; + + params = kstrdup(para, GFP_KERNEL); + params_base = params; + token = params; + len = strlen(token); + do { + token = strsep(¶ms, " "); + while (token && (isspace(*token) + || !isgraph(*token)) && len) { + token++; + len--; + } + if (len == 0) + break; + ret = kstrtoint(token, 0, &res); + if (ret < 0) + break; + len = strlen(token); + *out++ = res; + count++; + } while ((token) && (count < para_num) && (len > 0)); + + kfree(params_base); + return count; +} + +static ssize_t loglevel_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + + len = snprintf(buf, 128, "%d\n", osd_log_level); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t loglevel_write_file( + struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + unsigned int log_level; + char buf[128]; + int ret = 0; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + ret = kstrtoint(buf, 0, &log_level); + osd_log_info("log_level: %d->%d\n", osd_log_level, log_level); + osd_log_level = log_level; + return count; +} + +static ssize_t debug_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[1024]; + char *help; + ssize_t len; + + help = osd_get_debug_hw(); + len = snprintf(buf, strlen(help), "%s", help); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t debug_write_file(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + osd_set_debug_hw(buf); + return count; +} + +static ssize_t osd_display_debug_read_file(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + u32 osd_display_debug_enable; + + osd_get_display_debug(&osd_display_debug_enable); + len = snprintf(buf, 128, "%d\n", osd_display_debug_enable); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t osd_display_debug_write_file(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + u32 osd_display_debug_enable; + int ret = 0; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + ret = kstrtoint(buf, 0, &osd_display_debug_enable); + osd_set_display_debug(osd_display_debug_enable); + return count; +} + +static ssize_t reset_status_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + unsigned int status; + + status = osd_get_reset_status(); + len = snprintf(buf, 128, "0x%x\n", status); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t blank_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + + len = snprintf(buf, 128, "%d\n", osd_enable[osd_id]); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t blank_write_file(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + int ret = 0; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + ret = kstrtoint(buf, 0, &osd_enable[osd_id]); + if (ret <= 0) + return -EFAULT; + osd_enable_hw(osd_id, (osd_enable[osd_id] != 0) ? 0 : 1); + return count; +} + +static ssize_t free_scale_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + unsigned int free_scale_enable; + + osd_get_free_scale_enable_hw(osd_id, &free_scale_enable); + len = snprintf(buf, PAGE_SIZE, "free_scale_enable:[0x%x]\n", + free_scale_enable); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t free_scale_write_file(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + unsigned int free_scale_enable; + int ret = 0; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + ret = kstrtoint(buf, 0, &free_scale_enable); + osd_set_free_scale_enable_hw(osd_id, free_scale_enable); + return count; +} + +static ssize_t free_scale_axis_read_file(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + int x, y, w, h; + + osd_get_free_scale_axis_hw(osd_id, &x, &y, &w, &h); + len = snprintf(buf, 128, "%d %d %d %d\n", x, y, w, h); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t free_scale_axis_write_file(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + int parsed[4]; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + if (likely(parse_para(buf, 4, parsed) == 4)) + osd_set_free_scale_axis_hw(osd_id, + parsed[0], parsed[1], parsed[2], parsed[3]); + else + osd_log_err("set free scale axis error\n"); + return count; +} + +static ssize_t window_axis_read_file(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + int x0, y0, x1, y1; + + osd_get_window_axis_hw(osd_id, &x0, &y0, &x1, &y1); + len = snprintf(buf, 128, "%d %d %d %d\n", + x0, y0, x1, y1); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t window_axis_write_file(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + int parsed[4]; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + if (likely(parse_para(buf, 4, parsed) == 4)) + osd_set_window_axis_hw(osd_id, + parsed[0], parsed[1], parsed[2], parsed[3]); + else + osd_log_err("set window axis error\n"); + return count; +} + +static ssize_t osd_reverse_read_file(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + char *str[4] = {"NONE", "ALL", "X_REV", "Y_REV"}; + unsigned int osd_reverse = 0; + + osd_get_reverse_hw(osd_id, &osd_reverse); + if (osd_reverse >= REVERSE_MAX) + osd_reverse = REVERSE_FALSE; + len = snprintf(buf, 128, "osd_reverse:[%s]\n", + str[osd_reverse]); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t osd_reverse_write_file(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + unsigned int osd_reverse = 0; + int ret = 0; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + ret = kstrtoint(buf, 0, &osd_reverse); + if (osd_reverse >= REVERSE_MAX) + osd_reverse = REVERSE_FALSE; + osd_set_reverse_hw(osd_id, osd_reverse); + return count; +} + +static ssize_t osd_order_read_file(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + unsigned int order = 0; + + osd_get_order_hw(osd_id, &order); + len = snprintf(buf, 128, "order:[0x%x]\n", order); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t osd_order_write_file(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + unsigned int order = 0; + int ret = 0; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + ret = kstrtoint(buf, 0, &order); + osd_set_order_hw(osd_id, order); + return count; +} + +static ssize_t osd_afbcd_read_file(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + ssize_t len; + unsigned int enable_afbcd = 0; + + enable_afbcd = osd_get_afbc(); + len = snprintf(buf, 128, "%d\n", enable_afbcd); + return simple_read_from_buffer(userbuf, count, ppos, buf, len); +} + +static ssize_t osd_afbcd_write_file(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + unsigned int enable_afbcd = 0; + int ret = 0; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + ret = kstrtoint(buf, 0, &enable_afbcd); + osd_log_info("afbc: %d\n", enable_afbcd); + osd_set_afbc(enable_afbcd); + return count; +} + +static ssize_t osd_clear_write_file(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[128]; + struct seq_file *s = file->private_data; + int osd_id = *(int *)s; + unsigned int osd_clear = 0; + int ret = 0; + + count = min_t(size_t, count, (sizeof(buf)-1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + buf[count] = 0; + ret = kstrtoint(buf, 0, &osd_clear); + osd_set_clear(osd_id, osd_clear); + return count; +} + + + +static const struct file_operations loglevel_file_ops = { + .open = simple_open, + .read = loglevel_read_file, + .write = loglevel_write_file, +}; + +static const struct file_operations debug_file_ops = { + .open = simple_open, + .read = debug_read_file, + .write = debug_write_file, +}; + +static const struct file_operations osd_display_debug_file_ops = { + .open = simple_open, + .read = osd_display_debug_read_file, + .write = osd_display_debug_write_file, +}; + +static const struct file_operations reset_status_file_ops = { + .open = simple_open, + .read = reset_status_read_file, +}; + +static const struct file_operations blank_file_ops = { + .open = simple_open, + .read = blank_read_file, + .write = blank_write_file, +}; + +static const struct file_operations free_scale_file_ops = { + .open = simple_open, + .read = free_scale_read_file, + .write = free_scale_write_file, +}; + +static const struct file_operations free_scale_axis_file_ops = { + .open = simple_open, + .read = free_scale_axis_read_file, + .write = free_scale_axis_write_file, +}; + +static const struct file_operations window_axis_file_ops = { + .open = simple_open, + .read = window_axis_read_file, + .write = window_axis_write_file, +}; + +static const struct file_operations osd_reverse_file_ops = { + .open = simple_open, + .read = osd_reverse_read_file, + .write = osd_reverse_write_file, +}; + +static const struct file_operations osd_order_file_ops = { + .open = simple_open, + .read = osd_order_read_file, + .write = osd_order_write_file, +}; + +static const struct file_operations osd_afbcd_file_ops = { + .open = simple_open, + .read = osd_afbcd_read_file, + .write = osd_afbcd_write_file, +}; + +static const struct file_operations osd_clear_file_ops = { + .open = simple_open, + .write = osd_clear_write_file, +}; + + + +struct osd_drm_debugfs_files_s { + const char *name; + const umode_t mode; + const struct file_operations *fops; +}; + +static struct osd_drm_debugfs_files_s osd_drm_debugfs_files[] = { + {"loglevel", S_IFREG | 0640, &loglevel_file_ops}, + {"debug", S_IFREG | 0640, &debug_file_ops}, + {"osd_display_debug", S_IFREG | 0640, &osd_display_debug_file_ops}, + {"reset_status", S_IFREG | 0440, &reset_status_file_ops}, + {"blank", S_IFREG | 0640, &blank_file_ops}, + {"free_scale", S_IFREG | 0640, &free_scale_file_ops}, + {"free_scale_axis", S_IFREG | 0640, &free_scale_axis_file_ops}, + {"window_axis", S_IFREG | 0640, &window_axis_file_ops}, + {"osd_reverse", S_IFREG | 0640, &osd_reverse_file_ops}, + {"order", S_IFREG | 0640, &osd_order_file_ops}, + {"osd_afbcd", S_IFREG | 0640, &osd_afbcd_file_ops}, + {"osd_clear", S_IFREG | 0220, &osd_clear_file_ops}, +}; + +void osd_drm_debugfs_add( + struct dentry **plane_debugfs_dir, + char *name, + int osd_id) +{ + struct dentry *ent; + int i; + + plane_osd_id[osd_id] = osd_id; + *plane_debugfs_dir = debugfs_create_dir(name, osd_debugfs_root); + if (!plane_debugfs_dir) + osd_log_info("debugfs_create_dir failed: name=%s\n", name); + + for (i = 0; i < ARRAY_SIZE(osd_drm_debugfs_files); i++) { + ent = debugfs_create_file(osd_drm_debugfs_files[i].name, + osd_drm_debugfs_files[i].mode, + *plane_debugfs_dir, &plane_osd_id[osd_id], + osd_drm_debugfs_files[i].fops); + if (!ent) + osd_log_info("debugfs create failed\n"); + } + +} +EXPORT_SYMBOL(osd_drm_debugfs_add); + +void osd_drm_debugfs_init(void) +{ + osd_debugfs_root = debugfs_create_dir("graphics", NULL); + if (!osd_debugfs_root) + pr_err("can't create debugfs dir\n"); +} +EXPORT_SYMBOL(osd_drm_debugfs_init); + +void osd_drm_debugfs_exit(void) +{ + debugfs_remove(osd_debugfs_root); +} +EXPORT_SYMBOL(osd_drm_debugfs_exit); + +void osd_drm_vsync_isr_handler(void) +{ + +#ifndef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_update_scan_mode(); + /* go through update list */ + walk_through_update_list(); + osd_update_3d_mode(); + osd_update_vsync_hit(); + osd_hw_reset(); +#else + if (get_cpu_type() != MESON_CPU_MAJOR_ID_AXG) + osd_rdma_interrupt_done_clear(); + else { + osd_update_scan_mode(); + /* go through update list */ + walk_through_update_list(); + osd_update_3d_mode(); + osd_update_vsync_hit(); + osd_hw_reset(); + } +#endif +} +EXPORT_SYMBOL(osd_drm_vsync_isr_handler); + +void osd_drm_plane_page_flip(struct osd_plane_map_s *plane_map) +{ + osd_page_flip(plane_map); +} +EXPORT_SYMBOL(osd_drm_plane_page_flip); + +void osd_drm_plane_enable_hw(u32 index, u32 enable) +{ + osd_enable_hw(index, enable); +} +EXPORT_SYMBOL(osd_drm_plane_enable_hw); + +int osd_drm_init(void) +{ + int ret; + + /* osd hw init */ + ret = osd_io_remap(); + if (!ret) { + osd_log_err("osd_io_remap failed\n"); + return -1; + } + /* init osd logo */ + ret = logo_work_init(); + if (ret == 0) + osd_init_hw(1, 0); + else + osd_init_hw(0, 0); + /* freescale switch from osd2 to osd1*/ + osd_log_info("freescale switch from osd2 to osd1\n"); + osd_set_free_scale_mode_hw(OSD2, 1); + osd_set_free_scale_enable_hw(OSD2, 0); + osd_set_free_scale_mode_hw(OSD1, 1); + osd_set_free_scale_axis_hw(OSD1, 0, 0, 1919, 1279); + osd_set_window_axis_hw(OSD1, 0, 0, 1919, 1279); + osd_set_free_scale_enable_hw(OSD1, 0x10001); + osd_enable_hw(OSD1, 1); + return 0; +} +EXPORT_SYMBOL(osd_drm_init); diff --git a/drivers/amlogic/media/osd/osd_drm.h b/drivers/amlogic/media/osd/osd_drm.h new file mode 100644 index 000000000000..92a606779097 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_drm.h @@ -0,0 +1,52 @@ +/* + * drivers/amlogic/media/osd/osd_drm.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef _OSD_DRM_H_ +#define _OSD_DRM_H_ + +struct osd_plane_map_s { + u32 plane_index; + u32 zorder; + u32 phy_addr; + u32 format; + u32 enable; + u32 src_x; + u32 src_y; + u32 src_w; + u32 src_h; + u32 dst_x; + u32 dst_y; + u32 dst_w; + u32 dst_h; + int byte_stride; + u32 reserve; +}; + +int osd_drm_init(void); +void osd_drm_debugfs_add( + struct dentry **plane_debugfs_dir, + char *name, + int osd_id); +void osd_drm_debugfs_init(void); +void osd_drm_debugfs_exit(void); + +void osd_drm_plane_page_flip(struct osd_plane_map_s *plane_map); +void osd_drm_plane_enable_hw(u32 index, u32 enable); +void osd_drm_vsync_isr_handler(void); + + +#endif diff --git a/drivers/amlogic/media/osd/osd_fb.c b/drivers/amlogic/media/osd/osd_fb.c index 587b8b9213e5..642afe61cce0 100644 --- a/drivers/amlogic/media/osd/osd_fb.c +++ b/drivers/amlogic/media/osd/osd_fb.c @@ -2807,9 +2807,9 @@ static int osd_probe(struct platform_device *pdev) /* init osd logo */ ret = logo_work_init(); if (ret == 0) - osd_init_hw(1); + osd_init_hw(1, 1); else - osd_init_hw(0); + osd_init_hw(0, 1); /* get buffer size from dt */ ret = of_property_read_u32_array(pdev->dev.of_node, diff --git a/drivers/amlogic/media/osd/osd_hw.c b/drivers/amlogic/media/osd/osd_hw.c index edd23f015125..07274dfb5915 100644 --- a/drivers/amlogic/media/osd/osd_hw.c +++ b/drivers/amlogic/media/osd/osd_hw.c @@ -63,6 +63,7 @@ #include "osd_hw.h" #include "osd_hw_def.h" +#include "osd_fb.h" #ifdef CONFIG_AMLOGIC_VSYNC_FIQ_ENABLE #define FIQ_VSYNC @@ -83,6 +84,9 @@ static DECLARE_WAIT_QUEUE_HEAD(osd_vsync_wq); static bool vsync_hit; static bool osd_update_window_axis; static int osd_afbc_dec_enable; +static u32 extern_canvas[2] = {EXTERN1_CANVAS, EXTERN2_CANVAS}; +static int ext_canvas_id; + static void osd_clone_pan(u32 index, u32 yoffset, int debug_flag); static void osd_set_dummy_data(u32 alpha); @@ -738,7 +742,7 @@ void osd_update_scan_mode(void) osd_update_interlace_mode(index); } -static inline void walk_through_update_list(void) +void walk_through_update_list(void) { u32 i, j; @@ -887,7 +891,6 @@ static int notify_to_amvideo(void) return 0; } /*************** end of GXL/GXM hardware alpha bug workaround ***************/ - #ifdef FIQ_VSYNC static irqreturn_t vsync_isr(int irq, void *dev_id) { @@ -924,7 +927,6 @@ static irqreturn_t vsync_isr(int irq, void *dev_id) #endif } - void osd_set_pxp_mode(u32 mode) { pxp_mode = mode; @@ -949,14 +951,16 @@ u32 osd_get_reset_status(void) void osd_wait_vsync_hw(void) { unsigned long timeout; + if (osd_hw.fb_drvier_probe) { + vsync_hit = false; - vsync_hit = false; - - if (pxp_mode) - timeout = msecs_to_jiffies(50); - else - timeout = HZ; - wait_event_interruptible_timeout(osd_vsync_wq, vsync_hit, timeout); + if (pxp_mode) + timeout = msecs_to_jiffies(50); + else + timeout = HZ; + wait_event_interruptible_timeout( + osd_vsync_wq, vsync_hit, timeout); + } } s32 osd_wait_vsync_event(void) @@ -2041,6 +2045,7 @@ void osd_set_display_debug(u32 osd_display_debug_enable) osd_hw.osd_display_debug = osd_display_debug_enable; } + #ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE enum { HAL_PIXEL_FORMAT_RGBA_8888 = 1, @@ -2050,8 +2055,6 @@ enum { HAL_PIXEL_FORMAT_BGRA_8888 = 5, }; -static u32 extern_canvas[2] = {EXTERN1_CANVAS, EXTERN2_CANVAS}; -static int ext_canvas_id; static bool use_ext; const struct color_bit_define_s extern_color_format_array[] = { /*32 bit color RGBA */ @@ -3918,11 +3921,12 @@ void osd_init_scan_mode(void) } } -void osd_init_hw(u32 logo_loaded) +void osd_init_hw(u32 logo_loaded, u32 osd_probe) { u32 group, idx, data32, data2; int err_num = 0; + osd_hw.fb_drvier_probe = osd_probe; osd_vpu_power_on(); if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) backup_regs_init(HW_RESET_AFBCD_REGS); @@ -4081,6 +4085,8 @@ void osd_init_hw(u32 logo_loaded) osd_hw.free_scale_mode[OSD2] = 1; osd_hw.buffer_alloc[OSD1] = 0; osd_hw.buffer_alloc[OSD2] = 0; + osd_hw.osd_clear[OSD1] = 0; + osd_hw.osd_clear[OSD2] = 0; if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXM) || (get_cpu_type() == MESON_CPU_MAJOR_ID_TXLX)) osd_reg_write(VPP_OSD_SC_DUMMY_DATA, 0x002020ff); @@ -4103,22 +4109,24 @@ void osd_init_hw(u32 logo_loaded) INIT_LIST_HEAD(&post_fence_list); mutex_init(&post_fence_list_lock); #endif -#ifdef FIQ_VSYNC - osd_hw.fiq_handle_item.handle = vsync_isr; - osd_hw.fiq_handle_item.key = (u32)vsync_isr; - osd_hw.fiq_handle_item.name = "osd_vsync"; - if (register_fiq_bridge_handle(&osd_hw.fiq_handle_item)) -#else - err_num = request_irq(int_viu_vsync, &vsync_isr, - IRQF_SHARED, "osd-vsync", osd_setup_hw); - if (err_num) -#endif - osd_log_err("can't request irq for vsync,err_num=%d\n", - -err_num); -#ifdef FIQ_VSYNC - request_fiq(INT_VIU_VSYNC, &osd_fiq_isr); -#endif + if (osd_hw.fb_drvier_probe) { +#ifdef FIQ_VSYNC + osd_hw.fiq_handle_item.handle = vsync_isr; + osd_hw.fiq_handle_item.key = (u32)vsync_isr; + osd_hw.fiq_handle_item.name = "osd_vsync"; + if (register_fiq_bridge_handle(&osd_hw.fiq_handle_item)) +#else + err_num = request_irq(int_viu_vsync, &vsync_isr, + IRQF_SHARED, "osd-vsync", osd_setup_hw); + if (err_num) +#endif + osd_log_err("can't request irq for vsync,err_num=%d\n", + -err_num); +#ifdef FIQ_VSYNC + request_fiq(INT_VIU_VSYNC, &osd_fiq_isr); +#endif + } #ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA if (get_cpu_type() != MESON_CPU_MAJOR_ID_AXG) osd_rdma_enable(1); @@ -4370,3 +4378,464 @@ void osd_restore_screen_info( *screen_size = (unsigned long)osd_hw.screen_size[index]; } + +void osd_set_clear(u32 index, u32 osd_clear) +{ + osd_hw.osd_clear[index] = osd_clear; +} + +static const struct color_bit_define_s *convert_panel_format(u32 format) +{ + const struct color_bit_define_s *color = NULL; + + switch (format) { + case COLOR_INDEX_02_PAL4: + case COLOR_INDEX_04_PAL16: + case COLOR_INDEX_08_PAL256: + case COLOR_INDEX_16_655: + case COLOR_INDEX_16_844: + case COLOR_INDEX_16_6442: + case COLOR_INDEX_16_4444_R: + case COLOR_INDEX_16_4642_R: + case COLOR_INDEX_16_1555_A: + case COLOR_INDEX_16_4444_A: + case COLOR_INDEX_16_565: + case COLOR_INDEX_24_6666_A: + case COLOR_INDEX_24_6666_R: + case COLOR_INDEX_24_8565: + case COLOR_INDEX_24_5658: + case COLOR_INDEX_24_888_B: + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_32_BGRX: + case COLOR_INDEX_32_XBGR: + case COLOR_INDEX_32_RGBX: + case COLOR_INDEX_32_XRGB: + case COLOR_INDEX_32_BGRA: + case COLOR_INDEX_32_ABGR: + case COLOR_INDEX_32_RGBA: + case COLOR_INDEX_32_ARGB: + case COLOR_INDEX_YUV_422: + color = &default_color_format_array[format]; + break; + } + return color; +} + +static bool osd_direct_render(struct osd_plane_map_s *plane_map) +{ + u32 index = plane_map->plane_index; + u32 phy_addr = plane_map->phy_addr; + u32 width_src, width_dst, height_src, height_dst; + u32 x_start, x_end, y_start, y_end; + bool freescale_update = false; + struct pandata_s freescale_dst[HW_OSD_COUNT]; + void *vaddr = NULL; + + phy_addr = phy_addr + plane_map->byte_stride * plane_map->src_y; + if (osd_hw.osd_clear[index]) { + vaddr = phys_to_virt(phy_addr); + if (vaddr) + memset(vaddr, 0x0, + plane_map->byte_stride*plane_map->src_h); + } + canvas_config(osd_hw.fb_gem[index].canvas_idx, + phy_addr, + plane_map->byte_stride, + plane_map->src_h, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); + + width_dst = osd_hw.free_dst_data_backup[index].x_end - + osd_hw.free_dst_data_backup[index].x_start + 1; + width_src = osd_hw.free_src_data_backup[index].x_end - + osd_hw.free_src_data_backup[index].x_start + 1; + + height_dst = osd_hw.free_dst_data_backup[index].y_end - + osd_hw.free_dst_data_backup[index].y_start + 1; + height_src = osd_hw.free_src_data_backup[index].y_end - + osd_hw.free_src_data_backup[index].y_start + 1; + osd_hw.free_scale_enable[index] = 1; + + if (osd_hw.free_scale_enable[index] || + (width_src != width_dst) || + (height_src != height_dst) || + (plane_map->src_w != plane_map->dst_w) || + (plane_map->src_h != plane_map->dst_h)) { + osd_hw.free_scale[index].h_enable = 1; + osd_hw.free_scale[index].v_enable = 1; + osd_hw.free_scale_enable[index] = 0x10001; + osd_hw.free_scale_mode[index] = 1; + if (osd_hw.free_scale_enable[index] != + osd_hw.free_scale_enable_backup[index]) { + osd_set_scan_mode(OSD1); + freescale_update = true; + } + + osd_hw.pandata[index].x_start = plane_map->src_x; + osd_hw.pandata[index].x_end = + plane_map->src_x + plane_map->src_w - 1; + osd_hw.pandata[index].y_start = 0; + osd_hw.pandata[index].y_end = plane_map->src_h - 1; + + freescale_dst[index].x_start = + osd_hw.free_dst_data_backup[index].x_start + + (plane_map->dst_x * width_dst) / width_src; + freescale_dst[index].x_end = + osd_hw.free_dst_data_backup[index].x_start + + ((plane_map->dst_x + plane_map->dst_w) * + width_dst) / width_src - 1; + + freescale_dst[index].y_start = + osd_hw.free_dst_data_backup[index].y_start + + (plane_map->dst_y * height_dst) / height_src; + freescale_dst[index].y_end = + osd_hw.free_dst_data_backup[index].y_start + + ((plane_map->dst_y + plane_map->dst_h) * + height_dst) / height_src - 1; + if (osd_hw.osd_reverse[OSD1] == REVERSE_TRUE) { + x_start = osd_hw.vinfo_width + - freescale_dst[index].x_end - 1; + y_start = osd_hw.vinfo_height + - freescale_dst[index].y_end - 1; + x_end = osd_hw.vinfo_width + - freescale_dst[index].x_start - 1; + y_end = osd_hw.vinfo_height + - freescale_dst[index].y_start - 1; + freescale_dst[index].x_start = x_start; + freescale_dst[index].y_start = y_start; + freescale_dst[index].x_end = x_end; + freescale_dst[index].y_end = y_end; + } else if (osd_hw.osd_reverse[OSD1] == REVERSE_X) { + x_start = osd_hw.vinfo_width + - freescale_dst[index].x_end - 1; + x_end = osd_hw.vinfo_width + - freescale_dst[index].x_start - 1; + freescale_dst[index].x_start = x_start; + freescale_dst[index].x_end = x_end; + + } else if (osd_hw.osd_reverse[OSD1] == REVERSE_Y) { + y_start = osd_hw.vinfo_height + - freescale_dst[index].y_end - 1; + y_end = osd_hw.vinfo_height + - freescale_dst[index].y_start - 1; + freescale_dst[index].y_start = y_start; + freescale_dst[index].y_end = y_end; + } + if (memcmp(&(osd_hw.free_src_data[index]), + &osd_hw.pandata[index], + sizeof(struct pandata_s)) != 0 || + memcmp(&(osd_hw.free_dst_data[index]), + &freescale_dst[index], + sizeof(struct pandata_s)) != 0) { + memcpy(&(osd_hw.free_src_data[index]), + &osd_hw.pandata[index], + sizeof(struct pandata_s)); + memcpy(&(osd_hw.free_dst_data[index]), + &freescale_dst[index], + sizeof(struct pandata_s)); + freescale_update = true; + + if ((height_dst != height_src) || + (width_dst != width_src)) + osd_set_dummy_data(0); + else + osd_set_dummy_data(0xff); + } + osd_log_dbg2("pandata x=%d,x_end=%d,y=%d,y_end=%d\n", + osd_hw.pandata[index].x_start, + osd_hw.pandata[index].x_end, + osd_hw.pandata[index].y_start, + osd_hw.pandata[index].y_end); + osd_log_dbg2("plane_map:src_x=%d,src_y=%d,src_w=%d,src_h=%d\n", + plane_map->src_x, + plane_map->src_y, + plane_map->src_w, + plane_map->src_h); + osd_log_dbg2("fence_map:dst_x=%d,dst_y=%d,dst_w=%d,dst_h=%d\n", + plane_map->dst_x, + plane_map->dst_y, + plane_map->dst_w, + plane_map->dst_h); + } else { + osd_hw.pandata[index].x_start = 0; + osd_hw.pandata[index].x_end = plane_map->src_w - 1; + osd_hw.pandata[index].y_start = 0; + osd_hw.pandata[index].y_end = plane_map->src_h - 1; + + osd_hw.dispdata[index].x_start = plane_map->dst_x; + osd_hw.dispdata[index].x_end = + plane_map->dst_x + plane_map->dst_w - 1; + osd_hw.dispdata[index].y_start = plane_map->dst_y; + osd_hw.dispdata[index].y_end = + plane_map->dst_y + plane_map->dst_h - 1; + if (osd_hw.osd_reverse[OSD1] == REVERSE_TRUE) { + x_start = osd_hw.vinfo_width + - osd_hw.dispdata[index].x_end - 1; + y_start = osd_hw.vinfo_height + - osd_hw.dispdata[index].y_end - 1; + x_end = osd_hw.vinfo_width + - osd_hw.dispdata[index].x_start - 1; + y_end = osd_hw.vinfo_height + - osd_hw.dispdata[index].y_start - 1; + osd_hw.dispdata[index].x_start = x_start; + osd_hw.dispdata[index].y_start = y_start; + osd_hw.dispdata[index].x_end = x_end; + osd_hw.dispdata[index].y_end = y_end; + } else if (osd_hw.osd_reverse[OSD1] == REVERSE_X) { + x_start = osd_hw.vinfo_width + - osd_hw.dispdata[index].x_end - 1; + x_end = osd_hw.vinfo_width + - osd_hw.dispdata[index].x_start - 1; + osd_hw.dispdata[index].x_start = x_start; + osd_hw.dispdata[index].x_end = x_end; + + } else if (osd_hw.osd_reverse[OSD1] == REVERSE_Y) { + y_start = osd_hw.vinfo_height + - osd_hw.dispdata[index].y_end - 1; + y_end = osd_hw.vinfo_height + - osd_hw.dispdata[index].y_start - 1; + osd_hw.dispdata[index].y_start = y_start; + osd_hw.dispdata[index].y_end = y_end; + } + } + return freescale_update; +} + +static void osd_cursor_move(struct osd_plane_map_s *plane_map) +{ + u32 index = plane_map->plane_index; + u32 phy_addr = plane_map->phy_addr; + u32 x_start, x_end, y_start, y_end; + u32 x, y; + void *vaddr = NULL; + struct pandata_s disp_tmp; + struct pandata_s free_dst_data_backup; + + if (index != OSD2) + return; + phy_addr = phy_addr + plane_map->byte_stride * plane_map->src_y; + if (osd_hw.osd_clear[index]) { + vaddr = phys_to_virt(phy_addr); + if (vaddr) + memset(vaddr, 0x0, + plane_map->byte_stride*plane_map->src_h); + } + canvas_config(osd_hw.fb_gem[index].canvas_idx, + phy_addr, + plane_map->byte_stride, + plane_map->src_h, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); + + + osd_hw.pandata[index].x_start = plane_map->src_x; + osd_hw.pandata[index].x_end = plane_map->src_w - 1; + osd_hw.pandata[index].y_start = plane_map->src_y; + osd_hw.pandata[index].y_end = plane_map->src_h - 1; + + if (osd_hw.free_scale_mode[OSD1]) { + if (osd_hw.free_scale_enable[OSD1]) + memcpy(&disp_tmp, &osd_hw.cursor_dispdata[OSD1], + sizeof(struct pandata_s)); + else + memcpy(&disp_tmp, &osd_hw.dispdata[OSD1], + sizeof(struct pandata_s)); + } else + memcpy(&disp_tmp, &osd_hw.dispdata[OSD1], + sizeof(struct pandata_s)); + memcpy(&free_dst_data_backup, + &osd_hw.free_dst_data_backup[OSD1], + sizeof(struct pandata_s)); + #if 0 + if (osd_hw.free_scale[OSD1].h_enable) + free_dst_data_backup.x_end = + osd_hw.free_dst_data_backup[OSD1].x_end * 2; + if (osd_hw.free_scale[OSD1].v_enable) + free_dst_data_backup.y_end = + osd_hw.free_dst_data_backup[OSD1].y_end * 2; + #endif + x = plane_map->dst_x; + y = plane_map->dst_y; + if (osd_hw.free_src_data_backup[OSD1].x_end > 0 && + free_dst_data_backup.x_end > 0) { + x = x * free_dst_data_backup.x_end / + osd_hw.free_src_data_backup[OSD1].x_end; + } + if (osd_hw.free_src_data_backup[OSD1].y_end > 0 && + free_dst_data_backup.y_end > 0) { + y = y * free_dst_data_backup.y_end / + osd_hw.free_src_data_backup[OSD1].y_end; + } + + /* + * Use pandata to show a partial cursor when it is at the edge because + * the registers can't have negative values and because we need to + * manually clip the cursor when it is past the edge. The edge is + * hardcoded to the OSD0 area. + */ + osd_hw.dispdata[OSD2].x_start = x; + osd_hw.dispdata[OSD2].y_start = y; + if (x < disp_tmp.x_start) { + /* if negative position, set osd to 0,y and pan. */ + if ((disp_tmp.x_start - x) < plane_map->src_w) { + osd_hw.pandata[OSD2].x_start = disp_tmp.x_start - x; + osd_hw.pandata[OSD2].x_end = plane_map->src_w - 1; + } + osd_hw.dispdata[OSD2].x_start = 0; + } else { + osd_hw.pandata[OSD2].x_start = 0; + if (x + plane_map->src_w > disp_tmp.x_end) { + /* + * if past positive edge, + * set osd to inside of the edge and pan. + */ + if (x < disp_tmp.x_end) + osd_hw.pandata[OSD2].x_end = disp_tmp.x_end - x; + } else + osd_hw.pandata[OSD2].x_end = plane_map->src_w - 1; + } + if (y < disp_tmp.y_start) { + if ((disp_tmp.y_start - y) < plane_map->src_h) { + osd_hw.pandata[OSD2].y_start = disp_tmp.y_start - y; + osd_hw.pandata[OSD2].y_end = plane_map->src_h - 1; + } + osd_hw.dispdata[OSD2].y_start = 0; + } else { + osd_hw.pandata[OSD2].y_start = 0; + if (y + plane_map->src_h > disp_tmp.y_end) { + if (y < disp_tmp.y_end) + osd_hw.pandata[OSD2].y_end = disp_tmp.y_end - y; + } else + osd_hw.pandata[OSD2].y_end = plane_map->src_h - 1; + } + osd_hw.dispdata[OSD2].x_end = osd_hw.dispdata[OSD2].x_start + + osd_hw.pandata[OSD2].x_end - osd_hw.pandata[OSD2].x_start; + osd_hw.dispdata[OSD2].y_end = osd_hw.dispdata[OSD2].y_start + + osd_hw.pandata[OSD2].y_end - osd_hw.pandata[OSD2].y_start; + + if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) { + x_start = osd_hw.vinfo_width + - osd_hw.dispdata[index].x_end - 1; + y_start = osd_hw.vinfo_height + - osd_hw.dispdata[index].y_end - 1; + x_end = osd_hw.vinfo_width + - osd_hw.dispdata[index].x_start - 1; + y_end = osd_hw.vinfo_height + - osd_hw.dispdata[index].y_start - 1; + osd_hw.dispdata[index].x_start = x_start; + osd_hw.dispdata[index].y_start = y_start; + osd_hw.dispdata[index].x_end = x_end; + osd_hw.dispdata[index].y_end = y_end; + } else if (osd_hw.osd_reverse[OSD2] == REVERSE_X) { + x_start = osd_hw.vinfo_width + - osd_hw.dispdata[index].x_end - 1; + x_end = osd_hw.vinfo_width + - osd_hw.dispdata[index].x_start - 1; + osd_hw.dispdata[index].x_start = x_start; + osd_hw.dispdata[index].x_end = x_end; + } else if (osd_hw.osd_reverse[OSD2] == REVERSE_Y) { + y_start = osd_hw.vinfo_height + - osd_hw.dispdata[index].y_end - 1; + y_end = osd_hw.vinfo_height + - osd_hw.dispdata[index].y_start - 1; + osd_hw.dispdata[index].y_start = y_start; + osd_hw.dispdata[index].y_end = y_end; + } + osd_log_dbg2("plane_map:src_x=%d,src_y=%d,src_w=%d,src_h=%d\n", + plane_map->src_x, + plane_map->src_y, + plane_map->src_w, + plane_map->src_h); + osd_log_dbg2("fence_map:dst_x=%d,dst_y=%d,dst_w=%d,dst_h=%d\n", + plane_map->dst_x, + plane_map->dst_y, + plane_map->dst_w, + plane_map->dst_h); + osd_log_dbg2("cursor pandata x=%d,x_end=%d,y=%d,y_end=%d\n", + osd_hw.pandata[index].x_start, + osd_hw.pandata[index].x_end, + osd_hw.pandata[index].y_start, + osd_hw.pandata[index].y_end); + osd_log_dbg2("cursor dispdata x=%d,x_end=%d,y=%d,y_end=%d\n", + osd_hw.dispdata[index].x_start, + osd_hw.dispdata[index].x_end, + osd_hw.dispdata[index].y_start, + osd_hw.dispdata[index].y_end); +} + +void osd_page_flip(struct osd_plane_map_s *plane_map) +{ + u32 index = plane_map->plane_index; + const struct color_bit_define_s *color = NULL; + bool freescale_update = false; + u32 osd_enable = 0; + const struct vinfo_s *vinfo; + + if (index >= 2) + return; + + osd_hw.buffer_alloc[index] = 1; + if (osd_hw.osd_fps_start) + osd_hw.osd_fps++; + + osd_enable = (plane_map->enable & 1) ? ENABLE : DISABLE; + vinfo = get_current_vinfo(); + if (vinfo) { + osd_hw.vinfo_width = vinfo->width; + osd_hw.vinfo_height = vinfo->height; + } + if (plane_map->phy_addr && plane_map->src_w + && plane_map->src_h && index == OSD1) { + osd_hw.fb_gem[index].canvas_idx = + extern_canvas[ext_canvas_id]; + ext_canvas_id ^= 1; + color = convert_panel_format(plane_map->format); + if (color) { + osd_hw.color_info[index] = color; + } else + osd_log_err("fence color format error %d\n", + plane_map->format); + + freescale_update = osd_direct_render(plane_map); + + if (index == OSD1 && + osd_hw.osd_afbcd[index].enable == ENABLE) + osd_hw.osd_afbcd[index].phy_addr = + plane_map->phy_addr; + osd_hw.reg[index][OSD_COLOR_MODE].update_func(); + osd_hw.reg[index][DISP_GEOMETRY].update_func(); + if ((osd_hw.free_scale_enable[index] + && osd_update_window_axis) + || freescale_update) { + if (!osd_hw.osd_display_debug) + osd_hw.reg[index][DISP_FREESCALE_ENABLE] + .update_func(); + osd_update_window_axis = false; + } + if ((osd_hw.osd_afbcd[index].enable == DISABLE) + && (osd_enable != osd_hw.enable[index])) { + osd_hw.enable[index] = osd_enable; + if (!osd_hw.osd_display_debug) + osd_hw.reg[index][OSD_ENABLE] + .update_func(); + } + osd_wait_vsync_hw(); + } else if (plane_map->phy_addr && plane_map->src_w + && plane_map->src_h && index == OSD2) { + color = convert_panel_format(plane_map->format); + if (color) { + osd_hw.color_info[index] = color; + } else + osd_log_err("fence color format error %d\n", + plane_map->format); + osd_cursor_move(plane_map); + osd_hw.reg[index][OSD_COLOR_MODE].update_func(); + osd_hw.reg[index][DISP_GEOMETRY].update_func(); + if (osd_enable != osd_hw.enable[index]) { + osd_hw.enable[index] = osd_enable; + if (!osd_hw.osd_display_debug) + osd_hw.reg[index][OSD_ENABLE] + .update_func(); + } + + } +} + diff --git a/drivers/amlogic/media/osd/osd_hw.h b/drivers/amlogic/media/osd/osd_hw.h index 3d40d664e20f..7378ac0a5f8c 100644 --- a/drivers/amlogic/media/osd/osd_hw.h +++ b/drivers/amlogic/media/osd/osd_hw.h @@ -21,6 +21,7 @@ #include #include "osd.h" #include "osd_sync.h" +#include "osd_drm.h" #define REG_OFFSET (0x20) #define OSD_RELATIVE_BITS 0x33330 @@ -125,7 +126,7 @@ extern void osd_init_scan_mode(void); extern void osd_suspend_hw(void); extern void osd_resume_hw(void); extern void osd_shutdown_hw(void); -extern void osd_init_hw(u32 logo_loaded); +extern void osd_init_hw(u32 logo_loaded, u32 osd_probe); extern void osd_init_scan_mode(void); extern void osd_set_logo_index(int index); extern int osd_get_logo_index(void); @@ -167,4 +168,8 @@ void osd_restore_screen_info( u32 index, char __iomem **screen_base, unsigned long *screen_size); +void osd_set_clear(u32 index, u32 osd_clear); +void osd_page_flip(struct osd_plane_map_s *plane_map); +void walk_through_update_list(void); + #endif