11acafc73SSimon Glass /* 21acafc73SSimon Glass * Copyright (c) 2015 Google, Inc 31acafc73SSimon Glass * 41acafc73SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 51acafc73SSimon Glass */ 61acafc73SSimon Glass 71acafc73SSimon Glass #include <common.h> 81acafc73SSimon Glass #include <dm.h> 91acafc73SSimon Glass #include <mapmem.h> 101acafc73SSimon Glass #include <stdio_dev.h> 111acafc73SSimon Glass #include <video.h> 121acafc73SSimon Glass #include <video_console.h> 133016d3d4SKever Yang #ifdef CONFIG_DRM_ROCKCHIP 143016d3d4SKever Yang #include <video_rockchip.h> 153016d3d4SKever Yang #endif 161acafc73SSimon Glass #include <dm/lists.h> 171acafc73SSimon Glass #include <dm/device-internal.h> 181acafc73SSimon Glass #include <dm/uclass-internal.h> 191acafc73SSimon Glass #ifdef CONFIG_SANDBOX 201acafc73SSimon Glass #include <asm/sdl.h> 211acafc73SSimon Glass #endif 221acafc73SSimon Glass 231acafc73SSimon Glass /* 241acafc73SSimon Glass * Theory of operation: 251acafc73SSimon Glass * 261acafc73SSimon Glass * Before relocation each device is bound. The driver for each device must 271acafc73SSimon Glass * set the @align and @size values in struct video_uc_platdata. This 281acafc73SSimon Glass * information represents the requires size and alignment of the frame buffer 291acafc73SSimon Glass * for the device. The values can be an over-estimate but cannot be too 301acafc73SSimon Glass * small. The actual values will be suppled (in the same manner) by the bind() 311acafc73SSimon Glass * method after relocation. 321acafc73SSimon Glass * 331acafc73SSimon Glass * This information is then picked up by video_reserve() which works out how 341acafc73SSimon Glass * much memory is needed for all devices. This is allocated between 351acafc73SSimon Glass * gd->video_bottom and gd->video_top. 361acafc73SSimon Glass * 371acafc73SSimon Glass * After relocation the same process occurs. The driver supplies the same 381acafc73SSimon Glass * @size and @align information and this time video_post_bind() checks that 391acafc73SSimon Glass * the drivers does not overflow the allocated memory. 401acafc73SSimon Glass * 411acafc73SSimon Glass * The frame buffer address is actually set (to plat->base) in 421acafc73SSimon Glass * video_post_probe(). This function also clears the frame buffer and 431acafc73SSimon Glass * allocates a suitable text console device. This can then be used to write 441acafc73SSimon Glass * text to the video device. 451acafc73SSimon Glass */ 461acafc73SSimon Glass DECLARE_GLOBAL_DATA_PTR; 471acafc73SSimon Glass 4868dcdc99SSimon Glass void video_set_flush_dcache(struct udevice *dev, bool flush) 4968dcdc99SSimon Glass { 5068dcdc99SSimon Glass struct video_priv *priv = dev_get_uclass_priv(dev); 5168dcdc99SSimon Glass 5268dcdc99SSimon Glass priv->flush_dcache = flush; 5368dcdc99SSimon Glass } 5468dcdc99SSimon Glass 551acafc73SSimon Glass static ulong alloc_fb(struct udevice *dev, ulong *addrp) 561acafc73SSimon Glass { 571acafc73SSimon Glass struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 581acafc73SSimon Glass ulong base, align, size; 591acafc73SSimon Glass 603968398eSBin Meng if (!plat->size) 613968398eSBin Meng return 0; 623968398eSBin Meng 631acafc73SSimon Glass align = plat->align ? plat->align : 1 << 20; 641acafc73SSimon Glass base = *addrp - plat->size; 651acafc73SSimon Glass base &= ~(align - 1); 661acafc73SSimon Glass plat->base = base; 671acafc73SSimon Glass size = *addrp - base; 681acafc73SSimon Glass *addrp = base; 691acafc73SSimon Glass 701acafc73SSimon Glass return size; 711acafc73SSimon Glass } 721acafc73SSimon Glass 731acafc73SSimon Glass int video_reserve(ulong *addrp) 741acafc73SSimon Glass { 752f37ae52SKever Yang #ifndef CONFIG_DRM_ROCKCHIP 761acafc73SSimon Glass struct udevice *dev; 772f37ae52SKever Yang #endif 781acafc73SSimon Glass ulong size; 791acafc73SSimon Glass 801acafc73SSimon Glass gd->video_top = *addrp; 813016d3d4SKever Yang #ifdef CONFIG_DRM_ROCKCHIP 82*6414e3bcSSandy Huang int cubic_lut_step = CONFIG_ROCKCHIP_CUBIC_LUT_SIZE; 83*6414e3bcSSandy Huang /* This is depend on IC designed */ 84*6414e3bcSSandy Huang ulong cubic_lut_size = (cubic_lut_step * cubic_lut_step * cubic_lut_step + 1) / 2 * 16; 85*6414e3bcSSandy Huang /* Max support 4 cubic lut */ 86*6414e3bcSSandy Huang cubic_lut_size = roundup(cubic_lut_size, PAGE_SIZE) << 2; 87*6414e3bcSSandy Huang 88*6414e3bcSSandy Huang size = DRM_ROCKCHIP_FB_SIZE + MEMORY_POOL_SIZE + cubic_lut_size; 893016d3d4SKever Yang *addrp = *addrp - size; 903016d3d4SKever Yang *addrp &= ~((1 << 20) - 1); 910f3732faSJoseph Chen debug("Reserving %lx Bytes for video at: %lx\n", size, *addrp); 923016d3d4SKever Yang #else 931acafc73SSimon Glass for (uclass_find_first_device(UCLASS_VIDEO, &dev); 941acafc73SSimon Glass dev; 951acafc73SSimon Glass uclass_find_next_device(&dev)) { 961acafc73SSimon Glass size = alloc_fb(dev, addrp); 971acafc73SSimon Glass debug("%s: Reserving %lx bytes at %lx for video device '%s'\n", 981acafc73SSimon Glass __func__, size, *addrp, dev->name); 991acafc73SSimon Glass } 1003016d3d4SKever Yang #endif 1011acafc73SSimon Glass gd->video_bottom = *addrp; 1021acafc73SSimon Glass debug("Video frame buffers from %lx to %lx\n", gd->video_bottom, 1031acafc73SSimon Glass gd->video_top); 1041acafc73SSimon Glass 1051acafc73SSimon Glass return 0; 1061acafc73SSimon Glass } 1071acafc73SSimon Glass 1081acafc73SSimon Glass static int video_clear(struct udevice *dev) 1091acafc73SSimon Glass { 1101acafc73SSimon Glass struct video_priv *priv = dev_get_uclass_priv(dev); 1111acafc73SSimon Glass 1121acafc73SSimon Glass if (priv->bpix == VIDEO_BPP32) { 1131acafc73SSimon Glass u32 *ppix = priv->fb; 1141acafc73SSimon Glass u32 *end = priv->fb + priv->fb_size; 1151acafc73SSimon Glass 1161acafc73SSimon Glass while (ppix < end) 1171acafc73SSimon Glass *ppix++ = priv->colour_bg; 1181acafc73SSimon Glass } else { 1191acafc73SSimon Glass memset(priv->fb, priv->colour_bg, priv->fb_size); 1201acafc73SSimon Glass } 1211acafc73SSimon Glass 1221acafc73SSimon Glass return 0; 1231acafc73SSimon Glass } 1241acafc73SSimon Glass 1251acafc73SSimon Glass /* Flush video activity to the caches */ 1261acafc73SSimon Glass void video_sync(struct udevice *vid) 1271acafc73SSimon Glass { 1281acafc73SSimon Glass /* 1291acafc73SSimon Glass * flush_dcache_range() is declared in common.h but it seems that some 1301acafc73SSimon Glass * architectures do not actually implement it. Is there a way to find 1311acafc73SSimon Glass * out whether it exists? For now, ARM is safe. 1321acafc73SSimon Glass */ 1331acafc73SSimon Glass #if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF) 1341acafc73SSimon Glass struct video_priv *priv = dev_get_uclass_priv(vid); 1351acafc73SSimon Glass 1361acafc73SSimon Glass if (priv->flush_dcache) { 1371acafc73SSimon Glass flush_dcache_range((ulong)priv->fb, 1387981394eSSimon Glass ALIGN((ulong)priv->fb + priv->fb_size, 1397981394eSSimon Glass CONFIG_SYS_CACHELINE_SIZE)); 1401acafc73SSimon Glass } 1411acafc73SSimon Glass #elif defined(CONFIG_VIDEO_SANDBOX_SDL) 1421acafc73SSimon Glass struct video_priv *priv = dev_get_uclass_priv(vid); 1431acafc73SSimon Glass static ulong last_sync; 1441acafc73SSimon Glass 1451acafc73SSimon Glass if (get_timer(last_sync) > 10) { 1461acafc73SSimon Glass sandbox_sdl_sync(priv->fb); 1471acafc73SSimon Glass last_sync = get_timer(0); 1481acafc73SSimon Glass } 1491acafc73SSimon Glass #endif 1501acafc73SSimon Glass } 1511acafc73SSimon Glass 1521acafc73SSimon Glass void video_sync_all(void) 1531acafc73SSimon Glass { 1541acafc73SSimon Glass struct udevice *dev; 1551acafc73SSimon Glass 1561acafc73SSimon Glass for (uclass_find_first_device(UCLASS_VIDEO, &dev); 1571acafc73SSimon Glass dev; 1581acafc73SSimon Glass uclass_find_next_device(&dev)) { 1591acafc73SSimon Glass if (device_active(dev)) 1601acafc73SSimon Glass video_sync(dev); 1611acafc73SSimon Glass } 1621acafc73SSimon Glass } 1631acafc73SSimon Glass 1641acafc73SSimon Glass int video_get_xsize(struct udevice *dev) 1651acafc73SSimon Glass { 1661acafc73SSimon Glass struct video_priv *priv = dev_get_uclass_priv(dev); 1671acafc73SSimon Glass 1681acafc73SSimon Glass return priv->xsize; 1691acafc73SSimon Glass } 1701acafc73SSimon Glass 1711acafc73SSimon Glass int video_get_ysize(struct udevice *dev) 1721acafc73SSimon Glass { 1731acafc73SSimon Glass struct video_priv *priv = dev_get_uclass_priv(dev); 1741acafc73SSimon Glass 1751acafc73SSimon Glass return priv->ysize; 1761acafc73SSimon Glass } 1771acafc73SSimon Glass 1781acafc73SSimon Glass /* Set up the colour map */ 1791acafc73SSimon Glass static int video_pre_probe(struct udevice *dev) 1801acafc73SSimon Glass { 1811acafc73SSimon Glass struct video_priv *priv = dev_get_uclass_priv(dev); 1821acafc73SSimon Glass 1831acafc73SSimon Glass priv->cmap = calloc(256, sizeof(ushort)); 1841acafc73SSimon Glass if (!priv->cmap) 1851acafc73SSimon Glass return -ENOMEM; 1861acafc73SSimon Glass 1871acafc73SSimon Glass return 0; 1881acafc73SSimon Glass } 1891acafc73SSimon Glass 1901acafc73SSimon Glass static int video_pre_remove(struct udevice *dev) 1911acafc73SSimon Glass { 1921acafc73SSimon Glass struct video_priv *priv = dev_get_uclass_priv(dev); 1931acafc73SSimon Glass 1941acafc73SSimon Glass free(priv->cmap); 1951acafc73SSimon Glass 1961acafc73SSimon Glass return 0; 1971acafc73SSimon Glass } 1981acafc73SSimon Glass 1991acafc73SSimon Glass /* Set up the display ready for use */ 2001acafc73SSimon Glass static int video_post_probe(struct udevice *dev) 2011acafc73SSimon Glass { 2021acafc73SSimon Glass struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 2031acafc73SSimon Glass struct video_priv *priv = dev_get_uclass_priv(dev); 2041acafc73SSimon Glass char name[30], drv[15], *str; 205826f35f9SSimon Glass const char *drv_name = drv; 2061acafc73SSimon Glass struct udevice *cons; 2071acafc73SSimon Glass int ret; 2081acafc73SSimon Glass 2091acafc73SSimon Glass /* Set up the line and display size */ 2101acafc73SSimon Glass priv->fb = map_sysmem(plat->base, plat->size); 2111acafc73SSimon Glass priv->line_length = priv->xsize * VNBYTES(priv->bpix); 2121acafc73SSimon Glass priv->fb_size = priv->line_length * priv->ysize; 2131acafc73SSimon Glass 2141acafc73SSimon Glass /* Set up colours - we could in future support other colours */ 2151acafc73SSimon Glass #ifdef CONFIG_SYS_WHITE_ON_BLACK 2161acafc73SSimon Glass priv->colour_fg = 0xffffff; 2171acafc73SSimon Glass #else 2181acafc73SSimon Glass priv->colour_bg = 0xffffff; 2191acafc73SSimon Glass #endif 2201acafc73SSimon Glass video_clear(dev); 2211acafc73SSimon Glass 22283510766SSimon Glass /* 223826f35f9SSimon Glass * Create a text console device. For now we always do this, although 22483510766SSimon Glass * it might be useful to support only bitmap drawing on the device 225826f35f9SSimon Glass * for boards that don't need to display text. We create a TrueType 226826f35f9SSimon Glass * console if enabled, a rotated console if the video driver requests 227826f35f9SSimon Glass * it, otherwise a normal console. 228826f35f9SSimon Glass * 229826f35f9SSimon Glass * The console can be override by setting vidconsole_drv_name before 230826f35f9SSimon Glass * probing this video driver, or in the probe() method. 231826f35f9SSimon Glass * 232826f35f9SSimon Glass * TrueType does not support rotation at present so fall back to the 233826f35f9SSimon Glass * rotated console in that case. 23483510766SSimon Glass */ 235826f35f9SSimon Glass if (!priv->rot && IS_ENABLED(CONFIG_CONSOLE_TRUETYPE)) { 236a29b0120SSimon Glass snprintf(name, sizeof(name), "%s.vidconsole_tt", dev->name); 237a29b0120SSimon Glass strcpy(drv, "vidconsole_tt"); 238a29b0120SSimon Glass } else { 239a29b0120SSimon Glass snprintf(name, sizeof(name), "%s.vidconsole%d", dev->name, 240a29b0120SSimon Glass priv->rot); 241a29b0120SSimon Glass snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot); 242a29b0120SSimon Glass } 243a29b0120SSimon Glass 24483510766SSimon Glass str = strdup(name); 24583510766SSimon Glass if (!str) 24683510766SSimon Glass return -ENOMEM; 247826f35f9SSimon Glass if (priv->vidconsole_drv_name) 248826f35f9SSimon Glass drv_name = priv->vidconsole_drv_name; 249826f35f9SSimon Glass ret = device_bind_driver(dev, drv_name, str, &cons); 25083510766SSimon Glass if (ret) { 25183510766SSimon Glass debug("%s: Cannot bind console driver\n", __func__); 25283510766SSimon Glass return ret; 25383510766SSimon Glass } 254826f35f9SSimon Glass 25583510766SSimon Glass ret = device_probe(cons); 25683510766SSimon Glass if (ret) { 25783510766SSimon Glass debug("%s: Cannot probe console driver\n", __func__); 25883510766SSimon Glass return ret; 25983510766SSimon Glass } 26083510766SSimon Glass 2611acafc73SSimon Glass return 0; 2621acafc73SSimon Glass }; 2631acafc73SSimon Glass 2641acafc73SSimon Glass /* Post-relocation, allocate memory for the frame buffer */ 2651acafc73SSimon Glass static int video_post_bind(struct udevice *dev) 2661acafc73SSimon Glass { 2671acafc73SSimon Glass ulong addr = gd->video_top; 2681acafc73SSimon Glass ulong size; 2691acafc73SSimon Glass 2701acafc73SSimon Glass /* Before relocation there is nothing to do here */ 2711acafc73SSimon Glass if ((!gd->flags & GD_FLG_RELOC)) 2721acafc73SSimon Glass return 0; 2731acafc73SSimon Glass size = alloc_fb(dev, &addr); 2741acafc73SSimon Glass if (addr < gd->video_bottom) { 2751acafc73SSimon Glass /* Device tree node may need the 'u-boot,dm-pre-reloc' tag */ 2761acafc73SSimon Glass printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n", 2771acafc73SSimon Glass dev->name); 2781acafc73SSimon Glass return -ENOSPC; 2791acafc73SSimon Glass } 2801acafc73SSimon Glass debug("%s: Claiming %lx bytes at %lx for video device '%s'\n", 2811acafc73SSimon Glass __func__, size, addr, dev->name); 2821acafc73SSimon Glass gd->video_bottom = addr; 2831acafc73SSimon Glass 2841acafc73SSimon Glass return 0; 2851acafc73SSimon Glass } 2861acafc73SSimon Glass 2871acafc73SSimon Glass UCLASS_DRIVER(video) = { 2881acafc73SSimon Glass .id = UCLASS_VIDEO, 2891acafc73SSimon Glass .name = "video", 2901acafc73SSimon Glass .flags = DM_UC_FLAG_SEQ_ALIAS, 2911acafc73SSimon Glass .post_bind = video_post_bind, 2921acafc73SSimon Glass .pre_probe = video_pre_probe, 2931acafc73SSimon Glass .post_probe = video_post_probe, 2941acafc73SSimon Glass .pre_remove = video_pre_remove, 2951acafc73SSimon Glass .per_device_auto_alloc_size = sizeof(struct video_priv), 2961acafc73SSimon Glass .per_device_platdata_auto_alloc_size = sizeof(struct video_uc_platdata), 2971acafc73SSimon Glass }; 298