1 /* 2 * LCD peripheral support for the JZ4740 and related SoCs. 3 * 4 * Copyright (C) Xiangfu Liu <xiangfu@sharism.cc> 5 * Copyright (C) 2015, 2016, 2017, 2018, 6 * 2020 Paul Boddie <paul@boddie.org.uk> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA 22 */ 23 24 #include <l4/devices/hw_mmio_register_block.h> 25 #include <l4/sys/cache.h> 26 #include <l4/sys/types.h> 27 28 #include "lcd-jz4780.h" 29 #include "lcd-jz4740-config.h" 30 #include "lcd-jz4740-regs.h" 31 32 #include <stdint.h> 33 34 35 36 // JZ4780-specific methods. 37 38 Lcd_jz4780_chip::Lcd_jz4780_chip(l4_addr_t addr, Jz4740_lcd_panel *panel) 39 : Lcd_jz4740_chip(addr, panel) 40 { 41 _burst_size = 64; // 64-word burst size available in the JZ4780 42 } 43 44 // Return colour depth control value. 45 // JZ4780 position details only. 46 47 uint32_t 48 Lcd_jz4780_chip::_position_bpp() 49 { 50 uint32_t value; 51 52 switch (_panel->bpp) 53 { 54 case 15: case 16: value = Position_bpp_15_16bpp; break; 55 case 18: case 24: value = Position_bpp_18_24bpp; break; 56 case 30: value = Position_bpp_30bpp; break; 57 default: value = 0; break; 58 } 59 60 return value << Position_bpp; 61 } 62 63 uint32_t 64 Lcd_jz4780_chip::_priority_transfer() 65 { 66 uint32_t length; 67 68 switch (_burst_size) 69 { 70 case 4: length = Priority_burst_4; break; 71 case 8: length = Priority_burst_8; break; 72 case 32: length = Priority_burst_32; break; 73 case 64: length = Priority_burst_64; break; 74 case 16: 75 default: length = Priority_burst_16; break; 76 } 77 78 return Priority_mode_arbiter | 79 (length << Priority_highest_burst) | 80 (511U << Priority_threshold2) | 81 (400U << Priority_threshold1) | 82 (256U << Priority_threshold0); 83 } 84 85 // Initialise a DMA descriptor for the JZ4780. The principal differences with 86 // earlier SoCs are the "new" descriptor fields which populate additional 87 // registers controlling OSD foreground planes, and the frame enable flag which 88 // allows the descriptors/planes to be disabled and left unused. 89 90 void 91 Lcd_jz4780_chip::_set_descriptor(struct Jz4740_lcd_descriptor &desc, 92 l4_addr_t source, l4_size_t size, 93 struct Jz4740_lcd_descriptor *next, 94 uint32_t flags, 95 bool frame_enable) 96 { 97 // In the command, indicate the number of words from the source for transfer. 98 99 desc.next = next; 100 desc.source = frame_enable ? source : 0; 101 desc.identifier = source; 102 desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) | 103 (frame_enable ? (1U << Command_frame_enable) : 0) | 104 flags; 105 106 // Initialise "new" descriptor fields. 107 108 desc.offset = 0; 109 desc.page_width = 0; 110 desc.command_position = (1U << Position_premultiply_lcd) | 111 ((frame_enable ? 1U : 3U) << Position_coefficient) | 112 _position_bpp(); 113 desc.fg_size = 0xff000000 | 114 ((_panel->height - 1) << 12) | 115 ((_panel->width - 1) << 0); 116 } 117 118 // HDMI-compatible JZ4780 configuration. 119 // Remarks in the Ingenic Linux 3.0.8 driver suggest that the JZ4775 and JZ4780 120 // do not support palettes. Here, multiple panels are also not supported. 121 122 void 123 Lcd_jz4780_chip::config(struct Jz4740_lcd_descriptor *desc_vaddr, 124 struct Jz4740_lcd_descriptor *desc_paddr, 125 l4_addr_t fb_paddr) 126 { 127 // Provide the first framebuffer descriptor in single and dual modes. 128 // Flip back and forth between any palette and the framebuffer. 129 130 _set_descriptor(desc_vaddr[0], get_framebuffer(0, fb_paddr), 131 get_aligned_size(), 132 desc_paddr, 133 _command_irq()); 134 135 // Provide the second framebuffer descriptor only in dual-panel mode. 136 // Only employ this descriptor in the second DMA channel. 137 138 _set_descriptor(desc_vaddr[1], get_framebuffer(1, fb_paddr), 139 get_aligned_size(), 140 desc_paddr + 1, 141 _command_irq(), 142 false); 143 144 // Flush cached structure data. 145 146 l4_cache_clean_data((unsigned long) desc_vaddr, 147 (unsigned long) desc_vaddr + get_descriptors_size()); 148 149 // Configure DMA by setting frame descriptor addresses. 150 151 // Provide the palette descriptor address first, if employed. 152 153 _regs[Desc_address_0] = (uint32_t) desc_paddr; 154 155 // Provide a descriptor for the second DMA channel, providing foreground 1. 156 157 _regs[Desc_address_1] = (uint32_t) (desc_paddr + 1); 158 159 // Initialise panel-related registers. 160 161 _init_panel(); 162 163 // Initialise the control and configuration registers. 164 // JZ4780 does not support bpp setting here. Otherwise, this is the same as 165 // with earlier SoCs. 166 167 _regs[Lcd_control] = _control_panel() | _control_transfer() | _control_irq(); 168 _regs[Lcd_config] = _panel->config; 169 170 // JZ4780-specific configuration. 171 // The RGB control register usage may be superfluous. 172 173 _regs[Rgb_control] = (1U << Rgb_format_enable) | Rgb_odd_line_rgb | Rgb_even_line_rgb; 174 _regs[Priority_level] = _priority_transfer(); 175 176 // Employ whole image alpha levels by default. 177 178 _regs[Osd_config] = (1U << Osd_config_enable) | 179 (1U << Osd_config_alpha_enable); 180 _regs[Alpha_levels] = ((255U << Alpha_level_fg1) & Alpha_level_fg1_mask) | 181 ((255U << Alpha_level_fg0) & Alpha_level_fg0_mask); 182 } 183 184 185 186 // C language interface functions. 187 188 void * 189 jz4780_lcd_init(l4_addr_t lcd_base, struct Jz4740_lcd_panel *panel) 190 { 191 return (void *) new Lcd_jz4780_chip(lcd_base, panel); 192 }