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