blob: 5714230f569f94dd4601d9c2934158c1d06ea2e2 [file]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2021 Amlogic, Inc. All rights reserved.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/dma-map-ops.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_reserved_mem.h>
#include <uapi/linux/sched/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/notifier.h>
#include <linux/clk.h>
#include <linux/cma.h>
#include <linux/of_address.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_rect.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_fb_dma_helper.h>
#ifdef CONFIG_AMLOGIC_DRM_USE_ION
#include "meson_gem.h"
#include "meson_fb.h"
#endif
#include "meson_drv.h"
#include "meson_vpu.h"
#include "meson_vpu_pipeline.h"
#include "meson_crtc.h"
#include "meson_logo.h"
#include "meson_hdmi.h"
#include "meson_plane.h"
#ifdef CONFIG_AMLOGIC_MEDIA_FB
#include <linux/amlogic/media/osd/osd_logo.h>
#endif
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/gki_module.h>
#include <linux/amlogic/aml_free_reserved.h>
#ifdef CONFIG_CMA
struct cma *cma_logo;
#endif
static char *strmode;
struct am_meson_logo logo;
static struct platform_device *gp_dev;
static unsigned long gem_mem_start, gem_mem_size;
static struct resource osd_mem_res;
static bool is_cma;
#ifdef MODULE
MODULE_PARM_DESC(outputmode, "outputmode");
__module_param_named(outputmode, logo.outputmode_t, charp, 0600);
#else
#ifndef CONFIG_AMLOGIC_MEDIA_FB
core_param(fb_width, logo.width, uint, 0644);
core_param(fb_height, logo.height, uint, 0644);
core_param(display_bpp, logo.bpp, uint, 0644);
#endif
core_param(outputmode, logo.outputmode_t, charp, 0644);
#endif
#ifndef CONFIG_AMLOGIC_MEDIA_FB
static u32 drm_logo_bpp = 16;
static u32 drm_logo_width = 1920;
static u32 drm_logo_height = 1080;
static int drm_logo_bpp_setup(char *str)
{
int ret;
ret = kstrtoint(str, 0, &drm_logo_bpp);
return ret;
}
__setup("display_bpp=", drm_logo_bpp_setup);
static u32 drm_logo_get_display_bpp(void)
{
return drm_logo_bpp;
}
static int drm_logo_width_setup(char *str)
{
int ret;
ret = kstrtoint(str, 0, &drm_logo_width);
return ret;
}
__setup("fb_width=", drm_logo_width_setup);
static u32 drm_logo_get_fb_width(void)
{
return drm_logo_width;
}
static int drm_logo_height_setup(char *str)
{
int ret;
ret = kstrtoint(str, 0, &drm_logo_height);
return ret;
}
__setup("fb_height=", drm_logo_height_setup);
static u32 drm_logo_get_fb_height(void)
{
return drm_logo_height;
}
#define OSD_INVALID_INFO 0xffffffff
#define OSD_FIRST_GROUP_START 1
#define OSD_SECOND_GROUP_START 4
#define OSD_END 7
static inline int str2lower(char *str)
{
while (*str != '\0') {
*str = tolower(*str);
str++;
}
return 0;
}
static struct osd_info_s osd_info = {
.index = 0,
.osd_reverse = 0,
};
static struct para_osd_info_s para_osd_info[OSD_END + 2] = {
/* head */
{
"head", OSD_INVALID_INFO,
OSD_END + 1, 1,
0, OSD_END + 1
},
/* dev */
{
"osd0", DEV_OSD0,
OSD_FIRST_GROUP_START - 1, OSD_FIRST_GROUP_START + 1,
OSD_FIRST_GROUP_START, OSD_SECOND_GROUP_START - 1
},
{
"osd1", DEV_OSD1,
OSD_FIRST_GROUP_START, OSD_FIRST_GROUP_START + 2,
OSD_FIRST_GROUP_START, OSD_SECOND_GROUP_START - 1
},
{
"all", DEV_ALL,
OSD_FIRST_GROUP_START + 1, OSD_FIRST_GROUP_START + 3,
OSD_FIRST_GROUP_START, OSD_SECOND_GROUP_START - 1
},
/* reverse_mode */
{
"false", REVERSE_FALSE,
OSD_SECOND_GROUP_START - 1, OSD_SECOND_GROUP_START + 1,
OSD_SECOND_GROUP_START, OSD_END
},
{
"true", REVERSE_TRUE,
OSD_SECOND_GROUP_START, OSD_SECOND_GROUP_START + 2,
OSD_SECOND_GROUP_START, OSD_END
},
{
"x_rev", REVERSE_X,
OSD_SECOND_GROUP_START + 1, OSD_SECOND_GROUP_START + 3,
OSD_SECOND_GROUP_START, OSD_END
},
{
"y_rev", REVERSE_Y,
OSD_SECOND_GROUP_START + 2, OSD_SECOND_GROUP_START + 4,
OSD_SECOND_GROUP_START, OSD_END
},
{
"tail", OSD_INVALID_INFO, OSD_END,
0, 0,
OSD_END + 1
},
};
static inline int install_osd_reverse_info(struct osd_info_s *init_osd_info,
char *para)
{
u32 i = 0;
static u32 tail = OSD_END + 1;
u32 first = para_osd_info[0].next_idx;
for (i = first; i < tail; i = para_osd_info[i].next_idx) {
if (strcmp(para_osd_info[i].name, para) == 0) {
u32 group_start = para_osd_info[i].cur_group_start;
u32 group_end = para_osd_info[i].cur_group_end;
u32 prev = para_osd_info[group_start].prev_idx;
u32 next = para_osd_info[group_end].next_idx;
switch (para_osd_info[i].cur_group_start) {
case OSD_FIRST_GROUP_START:
init_osd_info->index = para_osd_info[i].info;
break;
case OSD_SECOND_GROUP_START:
init_osd_info->osd_reverse =
para_osd_info[i].info;
break;
}
para_osd_info[prev].next_idx = next;
para_osd_info[next].prev_idx = prev;
return 0;
}
}
return 0;
}
static int drm_logo_reverse_setup(char *str)
{
char *ptr = str;
char sep[2];
char *option;
int count = 2;
char find = 0;
struct osd_info_s *init_osd_info;
if (!str)
return -EINVAL;
init_osd_info = &osd_info;
memset(init_osd_info, 0, sizeof(struct osd_info_s));
do {
if (!isalpha(*ptr) && !isdigit(*ptr)) {
find = 1;
break;
}
} while (*++ptr != '\0');
if (!find)
return -EINVAL;
sep[0] = *ptr;
sep[1] = '\0';
while ((count--) && (option = strsep(&str, sep))) {
str2lower(option);
install_osd_reverse_info(init_osd_info, option);
}
return 0;
}
__setup("osd_reverse=", drm_logo_reverse_setup);
void drm_logo_get_osd_reverse(u32 *index, u32 *reverse_type)
{
*index = osd_info.index;
*reverse_type = osd_info.osd_reverse;
}
#endif
struct para_pair_s {
char *name;
int value;
};
#ifdef CONFIG_AMLOGIC_MEMORY_EXTEND
#ifdef CONFIG_64BIT
static void free_reserved_highmem(unsigned long start, unsigned long end)
{
}
#else
static void free_reserved_highmem(unsigned long start, unsigned long end)
{
for (; start < end; ) {
free_highmem_page(phys_to_page(start));
start += PAGE_SIZE;
}
}
#endif
static void free_reserved_mem(unsigned long start, unsigned long size)
{
unsigned long end = PAGE_ALIGN(start + size);
struct page *page, *epage;
pr_info("%s %d logo start_addr=%lx, end=%lx\n", __func__, __LINE__, start, end);
page = phys_to_page(start);
if (PageHighMem(page)) {
free_reserved_highmem(start, end);
} else {
epage = phys_to_page(end);
if (!PageHighMem(epage)) {
aml_free_reserved_area(__va(start),
__va(end), 0, "fb-memory");
} else {
/* reserved area cross zone */
struct zone *zone;
unsigned long bound;
zone = page_zone(page);
bound = zone_end_pfn(zone);
aml_free_reserved_area(__va(start),
__va(bound << PAGE_SHIFT),
0, "fb-memory");
zone = page_zone(epage);
bound = zone->zone_start_pfn;
free_reserved_highmem(bound << PAGE_SHIFT, end);
}
}
}
#endif
void am_meson_free_logo_memory(void)
{
if (is_cma) {
phys_addr_t logo_addr = page_to_phys(logo.logo_page);
if (logo.size > 0 && logo.alloc_flag) {
#ifdef CONFIG_CMA
DRM_INFO("%s, free cma memory: addr:0x%pa,size:0x%x\n",
__func__, &logo_addr, logo.size);
cma_release(cma_logo, logo.logo_page, logo.size >> PAGE_SHIFT);
#endif
}
} else {
#ifdef CONFIG_AMLOGIC_MEMORY_EXTEND
free_reserved_mem(logo.start, logo.size);
DRM_INFO("%s, free none_cma memory: addr:0x%pa,size:0x%x\n",
__func__, &logo.start, logo.size);
#endif
}
logo.alloc_flag = 0;
}
static int am_meson_logo_info_update(struct meson_drm *priv)
{
if (is_cma)
logo.start = page_to_phys(logo.logo_page);
logo.alloc_flag = 1;
/*config 1080p logo as default*/
if (!logo.width || !logo.height) {
logo.width = 1920;
logo.height = 1080;
}
if (!logo.bpp)
logo.bpp = 16;
if (!logo.outputmode_t) {
strcpy(logo.outputmode, "1080p60hz");
} else {
strncpy(logo.outputmode, logo.outputmode_t, VMODE_NAME_LEN_MAX);
logo.outputmode[VMODE_NAME_LEN_MAX - 1] = '\0';
}
priv->logo = &logo;
return 0;
}
static int am_meson_logo_init_fb(struct drm_device *dev,
struct drm_framebuffer *fb, int idx)
{
struct am_meson_fb *meson_fb;
struct am_meson_logo *slogo;
struct meson_drm *priv = dev->dev_private;
slogo = kzalloc(sizeof(*slogo), GFP_KERNEL);
if (!slogo)
return -EFAULT;
memcpy(slogo, &logo, sizeof(struct am_meson_logo));
if (idx == VPP0) {
#ifdef CONFIG_AMLOGIC_VOUT_SERVE
strcpy(slogo->outputmode, get_vout_mode_uboot());
#endif
} else if (idx == VPP1) {
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
strcpy(slogo->outputmode, get_vout2_mode_uboot());
#endif
} else if (idx == VPP2) {
#ifdef CONFIG_AMLOGIC_VOUT3_SERVE
strcpy(slogo->outputmode, get_vout3_mode_uboot());
#endif
}
if (!strcmp("null", slogo->outputmode) ||
!strcmp("dummy_l", slogo->outputmode)) {
DRM_DEBUG("NULL MODE or DUMMY MODE, nothing to do.");
kfree(slogo);
return -EINVAL;
}
slogo->logo_page = logo.logo_page;
slogo->vaddr = logo.vaddr;
slogo->start = logo.start;
slogo->panel_index = priv->primary_plane_index[idx];
slogo->vpp_index = idx;
DRM_INFO("logo%d width=%d,height=%d,start_addr=0x%pa,size=%d\n",
idx, slogo->width, slogo->height, &slogo->start, slogo->size);
DRM_DEBUG("bpp=%d,alloc_flag=%d, osd_reverse=%d\n",
slogo->bpp, slogo->alloc_flag, slogo->osd_reverse);
DRM_DEBUG("outputmode=%s\n", slogo->outputmode);
meson_fb = to_am_meson_fb(fb);
meson_fb->logo = slogo;
return 0;
}
/*copy from update_output_state,
*TODO:sync with update_output_state
*/
static int am_meson_update_output_state(struct drm_atomic_state *state,
struct drm_mode_set *set)
{
struct drm_device *dev = set->crtc->dev;
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state;
struct drm_connector *connector;
struct drm_connector_state *new_conn_state;
int ret, i;
ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
state->acquire_ctx);
if (ret)
return ret;
/* First disable all connectors on the target crtc. */
ret = drm_atomic_add_affected_connectors(state, set->crtc);
if (ret)
return ret;
for_each_new_connector_in_state(state, connector, new_conn_state, i) {
if (new_conn_state->crtc == set->crtc) {
ret = drm_atomic_set_crtc_for_connector(new_conn_state,
NULL);
if (ret)
return ret;
/* Make sure legacy setCrtc always re-trains */
new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
}
}
/* Then set all connectors from set->connectors on the target crtc */
for (i = 0; i < set->num_connectors; i++) {
new_conn_state =
drm_atomic_get_connector_state(state,
set->connectors[i]);
if (IS_ERR(new_conn_state))
return PTR_ERR(new_conn_state);
ret = drm_atomic_set_crtc_for_connector(new_conn_state,
set->crtc);
if (ret)
return ret;
}
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
/* Don't update ->enable for the CRTC in the set_config request,
* since a mismatch would indicate a bug in the upper layers.
* The actual modeset code later on will catch any
* inconsistencies here.
*/
if (crtc == set->crtc)
continue;
if (!new_crtc_state->connector_mask) {
ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
NULL);
if (ret < 0)
return ret;
new_crtc_state->active = false;
}
}
return 0;
}
static int _am_meson_occupy_plane_config(struct drm_atomic_state *state,
struct drm_mode_set *set)
{
struct drm_crtc *crtc = set->crtc;
struct meson_drm *private = crtc->dev->dev_private;
struct am_osd_plane *osd_plane;
struct drm_plane_state *plane_state;
int i, hdisplay, vdisplay, ret;
for (i = 0; i < MESON_MAX_OSD; i++) {
osd_plane = private->osd_planes[i];
if (!osd_plane || osd_plane->osd_occupied)
break;
}
if (!osd_plane || !osd_plane->osd_occupied)
return 0;
plane_state = drm_atomic_get_plane_state(state, &osd_plane->base);
if (IS_ERR(plane_state))
return PTR_ERR(plane_state);
ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
if (ret != 0)
return ret;
drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
drm_atomic_set_fb_for_plane(plane_state, set->fb);
plane_state->crtc_x = 0;
plane_state->crtc_y = 0;
plane_state->crtc_w = hdisplay;
plane_state->crtc_h = vdisplay;
plane_state->src_x = 0;
plane_state->src_y = 0;
plane_state->src_w = 1280/*set->fb->width*/ << 16;
plane_state->src_h = 720/*set->fb->height*/ << 16;
plane_state->alpha = 1;
plane_state->zpos = 128;
return 0;
}
/*similar with __drm_atomic_helper_set_config,
*TODO:sync with __drm_atomic_helper_set_config
*/
int __am_meson_drm_set_config(struct drm_mode_set *set,
struct drm_atomic_state *state, int idx)
{
struct drm_crtc_state *crtc_state;
struct drm_plane_state *plane_state;
struct drm_crtc *crtc = set->crtc;
struct meson_drm *private = crtc->dev->dev_private;
struct am_meson_crtc_state *meson_crtc_state;
struct am_osd_plane *osd_plane;
struct am_meson_fb *meson_fb;
int hdisplay, vdisplay, ret;
unsigned int zpos = OSD_PLANE_BEGIN_ZORDER;
crtc_state = drm_atomic_get_crtc_state(state, crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
meson_fb = to_am_meson_fb(set->fb);
meson_crtc_state = to_am_meson_crtc_state(crtc_state);
if (meson_fb->logo->vpp_index == VPP0) {
#ifdef CONFIG_AMLOGIC_VOUT_SERVE
meson_crtc_state->uboot_mode_init = get_vout_mode_uboot_state();
#endif
} else if (meson_fb->logo->vpp_index == VPP1) {
#ifdef CONFIG_AMLOGIC_VOUT2_SERVE
meson_crtc_state->uboot_mode_init = get_vout2_mode_uboot_state();
#endif
} else if (meson_fb->logo->vpp_index == VPP2) {
#ifdef CONFIG_AMLOGIC_VOUT3_SERVE
meson_crtc_state->uboot_mode_init = get_vout3_mode_uboot_state();
#endif
}
DRM_DEBUG("uboot_mode_init=%d\n", meson_crtc_state->uboot_mode_init);
osd_plane = private->osd_planes[idx];
if (!osd_plane)
return -EINVAL;
plane_state = drm_atomic_get_plane_state(state, &osd_plane->base);
if (IS_ERR(plane_state))
return PTR_ERR(plane_state);
if (!set->mode) {
WARN_ON(set->fb);
WARN_ON(set->num_connectors);
ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
if (ret != 0)
return ret;
crtc_state->active = false;
ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
if (ret != 0)
return ret;
drm_atomic_set_fb_for_plane(plane_state, NULL);
goto commit;
}
WARN_ON(!set->fb);
WARN_ON(!set->num_connectors);
ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
if (ret != 0)
return ret;
crtc_state->active = true;
ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
if (ret != 0)
return ret;
drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
drm_atomic_set_fb_for_plane(plane_state, set->fb);
plane_state->crtc_x = 0;
plane_state->crtc_y = 0;
plane_state->crtc_w = hdisplay;
plane_state->crtc_h = vdisplay;
plane_state->src_x = set->x << 16;
plane_state->src_y = set->y << 16;
plane_state->zpos = zpos + osd_plane->plane_index;
switch (logo.osd_reverse) {
case 1:
plane_state->rotation = DRM_MODE_REFLECT_MASK;
break;
case 2:
plane_state->rotation = DRM_MODE_REFLECT_X;
break;
case 3:
plane_state->rotation = DRM_MODE_REFLECT_Y;
break;
default:
plane_state->rotation = DRM_MODE_ROTATE_0;
break;
}
if (drm_rotation_90_or_270(plane_state->rotation)) {
if (private->ui_config.ui_h)
plane_state->src_w = private->ui_config.ui_h << 16;
else
plane_state->src_w = set->fb->height << 16;
if (private->ui_config.ui_w)
plane_state->src_h = private->ui_config.ui_w << 16;
else
plane_state->src_h = set->fb->width << 16;
} else {
if (private->ui_config.ui_w)
plane_state->src_w = private->ui_config.ui_w << 16;
else
plane_state->src_w = set->fb->width << 16;
if (private->ui_config.ui_h)
plane_state->src_h = private->ui_config.ui_h << 16;
else
plane_state->src_h = set->fb->height << 16;
}
if (meson_fb->logo->vpp_index == VPP0)
_am_meson_occupy_plane_config(state, set);
commit:
ret = am_meson_update_output_state(state, set);
if (ret)
return ret;
return 0;
}
/*copy from drm_atomic_helper_set_config,
*TODO:sync with drm_atomic_helper_set_config
*/
static int am_meson_drm_set_config(struct drm_mode_set *set,
struct drm_modeset_acquire_ctx *ctx, int idx)
{
struct drm_atomic_state *state;
struct drm_crtc *crtc = set->crtc;
int ret = 0;
state = drm_atomic_state_alloc(crtc->dev);
if (!state)
return -ENOMEM;
state->acquire_ctx = ctx;
ret = __am_meson_drm_set_config(set, state, idx);
if (ret != 0)
goto fail;
ret = drm_atomic_commit(state);
fail:
drm_atomic_state_put(state);
return ret;
}
static void am_meson_load_logo(struct drm_device *dev,
struct drm_framebuffer *fb, int idx)
{
struct drm_mode_set set;
struct drm_display_mode *mode;
struct drm_connector **connector_set;
struct drm_connector *connector;
struct drm_modeset_acquire_ctx *ctx;
struct meson_drm *private = dev->dev_private;
struct am_meson_fb *meson_fb;
u32 found, num_modes;
DRM_DEBUG("%s idx[%d]\n", __func__, idx);
if (!logo.alloc_flag) {
DRM_INFO("%s: logo memory is not alloc\n", __func__);
return;
}
if (am_meson_logo_init_fb(dev, fb, idx)) {
DRM_DEBUG("vout%d logo is disabled!\n", idx + 1);
return;
}
meson_fb = to_am_meson_fb(fb);
/*init all connector and found matched uboot mode.*/
found = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
drm_modeset_lock_all(dev);
if (drm_modeset_is_locked(&dev->mode_config.connection_mutex))
drm_modeset_unlock(&dev->mode_config.connection_mutex);
num_modes = connector->funcs->fill_modes(connector,
dev->mode_config.max_width,
dev->mode_config.max_height);
drm_modeset_unlock_all(dev);
if (num_modes) {
list_for_each_entry(mode, &connector->modes, head) {
if (!strcmp(mode->name, meson_fb->logo->outputmode)) {
found = 1;
break;
}
}
if (found)
break;
}
DRM_DEBUG("Connector[%d] status[%d]\n",
connector->connector_type, connector->status);
}
if (found) {
DRM_INFO("Found Connector[%d] mode[%s]\n",
connector->connector_type, mode->name);
if (!strcmp("null", mode->name)) {
DRM_INFO("NULL MODE, nothing to do.");
return;
}
} else {
connector = NULL;
mode = NULL;
return;
}
connector_set = vmalloc(sizeof(struct drm_connector *));
if (!connector_set)
return;
DRM_DEBUG("mode flag %x\n", mode->flags);
connector_set[0] = connector;
set.crtc = &private->crtcs[idx]->base;
set.x = 0;
set.y = 0;
set.mode = mode;
set.crtc->mode = *mode;
set.connectors = connector_set;
set.num_connectors = 1;
set.fb = &meson_fb->base;
drm_modeset_lock_all(dev);
ctx = dev->mode_config.acquire_ctx;
if (am_meson_drm_set_config(&set, ctx, meson_fb->logo->panel_index))
DRM_INFO("[%s]am_meson_drm_set_config fail\n", __func__);
drm_modeset_unlock_all(dev);
vfree(connector_set);
}
static int parse_reserve_mem_resource(struct device_node *np,
struct resource *res)
{
int ret;
ret = of_address_to_resource(np, 0, res);
of_node_put(np);
return ret;
}
void am_meson_logo_init(struct drm_device *dev)
{
struct drm_mode_fb_cmd2 mode_cmd;
struct drm_framebuffer *fb;
struct meson_drm *private = dev->dev_private;
struct platform_device *pdev = to_platform_device(private->dev);
#ifdef CONFIG_CMA
struct reserved_mem *rmem = NULL;
struct device_node *np, *mem_node;
#endif
u32 reverse_type, osd_index;
int i, ret;
const char *compatible;
const int *reusable;
DRM_DEBUG("%s in[%d]\n", __func__, __LINE__);
gp_dev = pdev;
np = gp_dev->dev.of_node;
mem_node = of_parse_phandle(np, "memory-region", 0);
compatible = of_get_property(mem_node, "compatible", NULL);
reusable = of_get_property(mem_node, "reusable", NULL);
if (!strcmp(compatible, "shared-dma-pool") && reusable)
is_cma = true;
else
is_cma = false;
if (is_cma) {
DRM_INFO("allocate cmd mem\n");
ret = of_reserved_mem_device_init(&gp_dev->dev);
if (ret != 0) {
DRM_ERROR("failed to init reserved memory\n");
} else {
#ifdef CONFIG_CMA
if (mem_node) {
rmem = of_reserved_mem_lookup(mem_node);
of_node_put(mem_node);
if (rmem) {
logo.size = rmem->size;
DRM_DEBUG("of read %s reservememsize=0x%x, base %pa\n",
rmem->name, logo.size, &rmem->base);
}
} else {
DRM_ERROR("no memory-region\n");
}
cma_logo = dev_get_cma_area(&gp_dev->dev);
if (cma_logo) {
if (logo.size > 0) {
#if CONFIG_AMLOGIC_KERNEL_VERSION >= 14515
logo.logo_page = cma_alloc(cma_logo,
ALIGN(logo.size, PAGE_SIZE) >> PAGE_SHIFT,
0, GFP_KERNEL);
#else
logo.logo_page = cma_alloc(cma_logo,
ALIGN(logo.size, PAGE_SIZE) >> PAGE_SHIFT,
0, false);
#endif
if (!logo.logo_page)
DRM_ERROR("allocate buffer failed\n");
else
am_meson_logo_info_update(private);
DRM_INFO(" cma_alloc from %s start page %px-%px size %x\n",
cma_get_name(cma_logo),
logo.logo_page,
(void *)logo.start,
logo.size);
}
}
#endif
if (gem_mem_start) {
dma_declare_coherent_memory(dev->dev,
gem_mem_start,
gem_mem_start,
gem_mem_size);
DRM_INFO("meson drm mem_start = 0x%x, size = 0x%x\n",
(u32)gem_mem_start, (u32)gem_mem_size);
}
}
} else {
DRM_INFO("allocate reserved mem\n");
if (mem_node) {
ret = parse_reserve_mem_resource(mem_node, &osd_mem_res);
if (ret != 0) {
DRM_ERROR("failed to init none_cma memory\n");
} else {
logo.size = resource_size(&osd_mem_res);
logo.start = osd_mem_res.start;
DRM_INFO("of read reservememsize=0x%x--0x%x\n",
logo.size, (u32)logo.start);
}
if (logo.size > 0) {
logo.vaddr = memremap(logo.start, logo.size,
MEMREMAP_WB);
if (!logo.vaddr)
DRM_ERROR("allocate buffer failed\n");
else
am_meson_logo_info_update(private);
}
} else {
DRM_ERROR("no memory-region\n");
}
}
#ifdef CONFIG_AMLOGIC_MEDIA_FB
get_logo_osd_reverse(&osd_index, &reverse_type);
logo.osd_reverse = reverse_type;
logo.width = get_logo_fb_width();
logo.height = get_logo_fb_height();
logo.bpp = get_logo_display_bpp();
#else
drm_logo_get_osd_reverse(&osd_index, &reverse_type);
logo.osd_reverse = reverse_type;
logo.width = drm_logo_get_fb_width();
logo.height = drm_logo_get_fb_height();
logo.bpp = drm_logo_get_display_bpp();
#endif
if (!logo.bpp)
logo.bpp = 16;
if (logo.bpp == 16)
mode_cmd.pixel_format = DRM_FORMAT_RGB565;
else if (logo.bpp == 24)
mode_cmd.pixel_format = DRM_FORMAT_RGB888;
else
mode_cmd.pixel_format = DRM_FORMAT_XRGB8888;
mode_cmd.offsets[0] = 0;
mode_cmd.width = logo.width;
mode_cmd.height = logo.height;
mode_cmd.modifier[0] = DRM_FORMAT_MOD_LINEAR;
/*ToDo*/
mode_cmd.pitches[0] = ALIGN(mode_cmd.width * logo.bpp, 32) / 8;
fb = am_meson_fb_alloc(dev, &mode_cmd, NULL);
if (IS_ERR_OR_NULL(fb)) {
DRM_ERROR("drm fb allocate failed\n");
private->logo_show_done = true;
return;
}
/*Todo: the condition may need change according to the boot args*/
if (strmode && !strcmp("4", strmode))
DRM_INFO("current is strmode\n");
else
#ifndef CONFIG_AMLOGIC_ZAPPER_CUT
for (i = 0; i < private->num_crtcs; i++)
#endif
am_meson_load_logo(dev, fb, i);
if (drm_framebuffer_read_refcount(fb) > 1)
drm_framebuffer_put(fb);
DRM_DEBUG("drm_fb[id:%d,ref:%d]\n", fb->base.id, kref_read(&fb->base.refcount));
private->logo_show_done = true;
DRM_DEBUG("%s end[%d]\n", __func__, __LINE__);
}
static int gem_mem_device_init(struct reserved_mem *rmem, struct device *dev)
{
s32 ret = 0;
if (!rmem) {
pr_info("Can't get reverse mem!\n");
ret = -EFAULT;
return ret;
}
gem_mem_start = rmem->base;
gem_mem_size = rmem->size;
DRM_INFO("init gem memory source addr:0x%x size:0x%x\n",
(u32)gem_mem_start, (u32)gem_mem_size);
return 0;
}
static const struct reserved_mem_ops rmem_gem_ops = {
.device_init = gem_mem_device_init,
};
static int __init gem_mem_setup(struct reserved_mem *rmem)
{
rmem->ops = &rmem_gem_ops;
DRM_INFO("gem mem setup\n");
return 0;
}
RESERVEDMEM_OF_DECLARE(gem, "amlogic, gem_memory", gem_mem_setup);