18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2018 Loongson Technology Co., Ltd. 38c2ecf20Sopenharmony_ci * Authors: 48c2ecf20Sopenharmony_ci * Chen Zhu <zhuchen@loongson.cn> 58c2ecf20Sopenharmony_ci * Yaling Fang <fangyaling@loongson.cn> 68c2ecf20Sopenharmony_ci * Dandan Zhang <zhangdandan@loongson.cn> 78c2ecf20Sopenharmony_ci * Huacai Chen <chenhc@lemote.com> 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 98c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License as published by the 108c2ecf20Sopenharmony_ci * Free Software Foundation; either version 2 of the License, or (at your 118c2ecf20Sopenharmony_ci * option) any later version. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 158c2ecf20Sopenharmony_ci#include <drm/drm_gem_cma_helper.h> 168c2ecf20Sopenharmony_ci#include "loongson_drv.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic void flush_scache_range(void *addr, unsigned long size) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci int inc; 218c2ecf20Sopenharmony_ci unsigned long start, end; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci start = (unsigned long)addr; 248c2ecf20Sopenharmony_ci end = (unsigned long)addr + size; 258c2ecf20Sopenharmony_ci inc = cpu_last_level_cache_line_size(); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci for (; start < end; start += inc) 288c2ecf20Sopenharmony_ci flush_cache_line(Cache_LEAF3, start); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci Hide the cursor off screen. We can't disable the cursor hardware because it 338c2ecf20Sopenharmony_ci takes too long to re-activate and causes momentary corruption 348c2ecf20Sopenharmony_ci*/ 358c2ecf20Sopenharmony_cistatic void loongson_hide_cursor(struct drm_crtc *crtc) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci unsigned long flags; 388c2ecf20Sopenharmony_ci volatile void __iomem *base; 398c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 408c2ecf20Sopenharmony_ci struct loongson_drm_device *ldev = (struct loongson_drm_device *)dev->dev_private; 418c2ecf20Sopenharmony_ci struct loongson_crtc *loongson_crtc = to_loongson_crtc(crtc); 428c2ecf20Sopenharmony_ci unsigned int tmp, crtc_id = loongson_crtc->crtc_id; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci base = ldev->mmio; 458c2ecf20Sopenharmony_ci tmp = readl(base + FB_CUR_CFG_REG); 468c2ecf20Sopenharmony_ci tmp &= ~0xff; 478c2ecf20Sopenharmony_ci if (clone_mode(ldev)) { 488c2ecf20Sopenharmony_ci spin_lock_irqsave(&loongson_reglock, flags); 498c2ecf20Sopenharmony_ci writel(tmp | 0x00, base + FB_CUR_CFG_REG); 508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&loongson_reglock, flags); 518c2ecf20Sopenharmony_ci ldev->cursor_showed = false; 528c2ecf20Sopenharmony_ci } else { 538c2ecf20Sopenharmony_ci if (ldev->cursor_crtc_id != crtc_id) 548c2ecf20Sopenharmony_ci return; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci spin_lock_irqsave(&loongson_reglock, flags); 578c2ecf20Sopenharmony_ci if (crtc_id) { 588c2ecf20Sopenharmony_ci writel(tmp | 0x10, base + FB_CUR_CFG_REG); 598c2ecf20Sopenharmony_ci } else { 608c2ecf20Sopenharmony_ci writel(tmp | 0x00, base + FB_CUR_CFG_REG); 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&loongson_reglock, flags); 638c2ecf20Sopenharmony_ci ldev->cursor_showed = false; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void loongson_show_cursor(struct drm_crtc *crtc) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci unsigned long flags; 708c2ecf20Sopenharmony_ci volatile void __iomem *base; 718c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 728c2ecf20Sopenharmony_ci struct loongson_drm_device *ldev = (struct loongson_drm_device *)dev->dev_private; 738c2ecf20Sopenharmony_ci struct loongson_crtc *loongson_crtc = to_loongson_crtc(crtc); 748c2ecf20Sopenharmony_ci unsigned int crtc_id = loongson_crtc->crtc_id; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci base = ldev->mmio; 778c2ecf20Sopenharmony_ci if (clone_mode(ldev)) { 788c2ecf20Sopenharmony_ci spin_lock_irqsave(&loongson_reglock, flags); 798c2ecf20Sopenharmony_ci writel(0x00050202, base + FB_CUR_CFG_REG); 808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&loongson_reglock, flags); 818c2ecf20Sopenharmony_ci ldev->cursor_crtc_id = 0; 828c2ecf20Sopenharmony_ci ldev->cursor_showed = true; 838c2ecf20Sopenharmony_ci } else { 848c2ecf20Sopenharmony_ci if (ldev->cursor_crtc_id == crtc_id) { 858c2ecf20Sopenharmony_ci spin_lock_irqsave(&loongson_reglock, flags); 868c2ecf20Sopenharmony_ci if(crtc_id == 0){ 878c2ecf20Sopenharmony_ci writel(0x00050202, base + FB_CUR_CFG_REG); 888c2ecf20Sopenharmony_ci }else{ 898c2ecf20Sopenharmony_ci writel(0x00050212, base + FB_CUR_CFG_REG); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&loongson_reglock, flags); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci ldev->cursor_showed = true; 948c2ecf20Sopenharmony_ci ldev->cursor_crtc_id = crtc_id; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciint loongson_crtc_cursor_set2(struct drm_crtc *crtc, 1008c2ecf20Sopenharmony_ci struct drm_file *file_priv, 1018c2ecf20Sopenharmony_ci uint32_t handle, 1028c2ecf20Sopenharmony_ci uint32_t width, 1038c2ecf20Sopenharmony_ci uint32_t height, 1048c2ecf20Sopenharmony_ci int32_t hot_x, int32_t hot_y) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci u32 gpu_addr; 1078c2ecf20Sopenharmony_ci unsigned long flags; 1088c2ecf20Sopenharmony_ci unsigned int crtc_id; 1098c2ecf20Sopenharmony_ci volatile void __iomem *base; 1108c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 1118c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 1128c2ecf20Sopenharmony_ci struct loongson_crtc *loongson_crtc = to_loongson_crtc(crtc); 1138c2ecf20Sopenharmony_ci struct loongson_drm_device *ldev = (struct loongson_drm_device *)dev->dev_private; 1148c2ecf20Sopenharmony_ci struct drm_gem_cma_object *cma, *cursor = ldev->cursor; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci base = ldev->mmio; 1178c2ecf20Sopenharmony_ci crtc_id = loongson_crtc->crtc_id; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if ((width != 32 || height != 32) && handle) { 1208c2ecf20Sopenharmony_ci return -EINVAL; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!handle || !file_priv) { 1248c2ecf20Sopenharmony_ci loongson_hide_cursor(crtc); 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci obj = drm_gem_object_lookup(file_priv, handle); 1298c2ecf20Sopenharmony_ci if (!obj) 1308c2ecf20Sopenharmony_ci return -ENOENT; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci cma = to_drm_gem_cma_obj(obj); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci flush_scache_range(cma->vaddr, 32*32*4); 1358c2ecf20Sopenharmony_ci memcpy(cursor->vaddr, cma->vaddr, 32*32*4); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Program gpu address of cursor buffer */ 1388c2ecf20Sopenharmony_ci gpu_addr = ldev->cursor->paddr; 1398c2ecf20Sopenharmony_ci spin_lock_irqsave(&loongson_reglock, flags); 1408c2ecf20Sopenharmony_ci writel(gpu_addr, base + FB_CUR_ADDR_REG); 1418c2ecf20Sopenharmony_ci writel(0x00eeeeee, base + FB_CUR_BACK_REG); 1428c2ecf20Sopenharmony_ci writel(0x00aaaaaa, base + FB_CUR_FORE_REG); 1438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&loongson_reglock, flags); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci loongson_show_cursor(crtc); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci drm_gem_object_put(obj); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciint loongson_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci unsigned long flags; 1558c2ecf20Sopenharmony_ci unsigned int tmp, crtc_id; 1568c2ecf20Sopenharmony_ci int xorign = 0, yorign = 0; 1578c2ecf20Sopenharmony_ci volatile void __iomem *base; 1588c2ecf20Sopenharmony_ci struct loongson_crtc *loongson_crtc = to_loongson_crtc(crtc); 1598c2ecf20Sopenharmony_ci struct loongson_drm_device *ldev = (struct loongson_drm_device *)crtc->dev->dev_private; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci base = ldev->mmio; 1628c2ecf20Sopenharmony_ci crtc_id = loongson_crtc->crtc_id; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* upper edge condition */ 1658c2ecf20Sopenharmony_ci yorign = y + crtc->y; 1668c2ecf20Sopenharmony_ci if (yorign < 0) 1678c2ecf20Sopenharmony_ci y = 0; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* left edge conditon */ 1708c2ecf20Sopenharmony_ci xorign = x + crtc->x; 1718c2ecf20Sopenharmony_ci if (xorign < 0) 1728c2ecf20Sopenharmony_ci x = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* move from one crtc to another, check which crtc should he shown 1758c2ecf20Sopenharmony_ci * the x or y < 0, it means the cursor it out of current review, 1768c2ecf20Sopenharmony_ci * && xorign/ yorign > 0, it means the cursor is in the framebuffer 1778c2ecf20Sopenharmony_ci * but not in curren review */ 1788c2ecf20Sopenharmony_ci if ((x < 0 && xorign > 0) || (y < 0 && yorign > 0)) { 1798c2ecf20Sopenharmony_ci if(ldev->cursor_crtc_id == crtc_id && !clone_mode(ldev)) 1808c2ecf20Sopenharmony_ci /*the cursor is not show, so hide if the (x,y) is in active crtc*/ 1818c2ecf20Sopenharmony_ci loongson_hide_cursor(crtc); 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (x < 0) 1868c2ecf20Sopenharmony_ci x = 0; 1878c2ecf20Sopenharmony_ci if (y < 0) 1888c2ecf20Sopenharmony_ci y = 0; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci tmp = x & 0xffff; 1918c2ecf20Sopenharmony_ci tmp |= y << 16; 1928c2ecf20Sopenharmony_ci spin_lock_irqsave(&loongson_reglock, flags); 1938c2ecf20Sopenharmony_ci writel(tmp, base + FB_CUR_LOC_ADDR_REG); 1948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&loongson_reglock, flags); 1958c2ecf20Sopenharmony_ci if (ldev->cursor_crtc_id != crtc_id && !clone_mode(ldev)) { 1968c2ecf20Sopenharmony_ci ldev->cursor_crtc_id = crtc_id; 1978c2ecf20Sopenharmony_ci ldev->cursor_showed = false; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci if (!ldev->cursor_showed) 2008c2ecf20Sopenharmony_ci loongson_show_cursor(crtc); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 204