1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/devices/lib/lcd/src/jz4740/lcd-jz4780.cc Sat Jun 06 01:22:18 2020 +0200
1.3 @@ -0,0 +1,192 @@
1.4 +/*
1.5 + * LCD peripheral support for the JZ4740 and related SoCs.
1.6 + *
1.7 + * Copyright (C) Xiangfu Liu <xiangfu@sharism.cc>
1.8 + * Copyright (C) 2015, 2016, 2017, 2018,
1.9 + * 2020 Paul Boddie <paul@boddie.org.uk>
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or
1.12 + * modify it under the terms of the GNU General Public License as
1.13 + * published by the Free Software Foundation; either version 2 of
1.14 + * the License, or (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + *
1.21 + * You should have received a copy of the GNU General Public License
1.22 + * along with this program; if not, write to the Free Software
1.23 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.24 + * Boston, MA 02110-1301, USA
1.25 + */
1.26 +
1.27 +#include <l4/devices/hw_mmio_register_block.h>
1.28 +#include <l4/sys/cache.h>
1.29 +#include <l4/sys/types.h>
1.30 +
1.31 +#include "lcd-jz4780.h"
1.32 +#include "lcd-jz4740-config.h"
1.33 +#include "lcd-jz4740-regs.h"
1.34 +
1.35 +#include <stdint.h>
1.36 +
1.37 +
1.38 +
1.39 +// JZ4780-specific methods.
1.40 +
1.41 +Lcd_jz4780_chip::Lcd_jz4780_chip(l4_addr_t addr, Jz4740_lcd_panel *panel)
1.42 +: Lcd_jz4740_chip(addr, panel)
1.43 +{
1.44 + _burst_size = 64; // 64-word burst size available in the JZ4780
1.45 +}
1.46 +
1.47 +// Return colour depth control value.
1.48 +// JZ4780 position details only.
1.49 +
1.50 +uint32_t
1.51 +Lcd_jz4780_chip::_position_bpp()
1.52 +{
1.53 + uint32_t value;
1.54 +
1.55 + switch (_panel->bpp)
1.56 + {
1.57 + case 15: case 16: value = Position_bpp_15_16bpp; break;
1.58 + case 18: case 24: value = Position_bpp_18_24bpp; break;
1.59 + case 30: value = Position_bpp_30bpp; break;
1.60 + default: value = 0; break;
1.61 + }
1.62 +
1.63 + return value << Position_bpp;
1.64 +}
1.65 +
1.66 +uint32_t
1.67 +Lcd_jz4780_chip::_priority_transfer()
1.68 +{
1.69 + uint32_t length;
1.70 +
1.71 + switch (_burst_size)
1.72 + {
1.73 + case 4: length = Priority_burst_4; break;
1.74 + case 8: length = Priority_burst_8; break;
1.75 + case 32: length = Priority_burst_32; break;
1.76 + case 64: length = Priority_burst_64; break;
1.77 + case 16:
1.78 + default: length = Priority_burst_16; break;
1.79 + }
1.80 +
1.81 + return Priority_mode_arbiter |
1.82 + (length << Priority_highest_burst) |
1.83 + (511U << Priority_threshold2) |
1.84 + (400U << Priority_threshold1) |
1.85 + (256U << Priority_threshold0);
1.86 +}
1.87 +
1.88 +// Initialise a DMA descriptor for the JZ4780. The principal differences with
1.89 +// earlier SoCs are the "new" descriptor fields which populate additional
1.90 +// registers controlling OSD foreground planes, and the frame enable flag which
1.91 +// allows the descriptors/planes to be disabled and left unused.
1.92 +
1.93 +void
1.94 +Lcd_jz4780_chip::_set_descriptor(struct Jz4740_lcd_descriptor &desc,
1.95 + l4_addr_t source, l4_size_t size,
1.96 + struct Jz4740_lcd_descriptor *next,
1.97 + uint32_t flags,
1.98 + bool frame_enable)
1.99 +{
1.100 + // In the command, indicate the number of words from the source for transfer.
1.101 +
1.102 + desc.next = next;
1.103 + desc.source = frame_enable ? source : 0;
1.104 + desc.identifier = source;
1.105 + desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) |
1.106 + (frame_enable ? (1U << Command_frame_enable) : 0) |
1.107 + flags;
1.108 +
1.109 + // Initialise "new" descriptor fields.
1.110 +
1.111 + desc.offset = 0;
1.112 + desc.page_width = 0;
1.113 + desc.command_position = (1U << Position_premultiply_lcd) |
1.114 + ((frame_enable ? 1U : 3U) << Position_coefficient) |
1.115 + _position_bpp();
1.116 + desc.fg_size = 0xff000000 |
1.117 + ((_panel->height - 1) << 12) |
1.118 + ((_panel->width - 1) << 0);
1.119 +}
1.120 +
1.121 +// HDMI-compatible JZ4780 configuration.
1.122 +// Remarks in the Ingenic Linux 3.0.8 driver suggest that the JZ4775 and JZ4780
1.123 +// do not support palettes. Here, multiple panels are also not supported.
1.124 +
1.125 +void
1.126 +Lcd_jz4780_chip::config(struct Jz4740_lcd_descriptor *desc_vaddr,
1.127 + struct Jz4740_lcd_descriptor *desc_paddr,
1.128 + l4_addr_t fb_paddr)
1.129 +{
1.130 + // Provide the first framebuffer descriptor in single and dual modes.
1.131 + // Flip back and forth between any palette and the framebuffer.
1.132 +
1.133 + _set_descriptor(desc_vaddr[0], get_framebuffer(0, fb_paddr),
1.134 + get_aligned_size(),
1.135 + desc_paddr,
1.136 + _command_irq());
1.137 +
1.138 + // Provide the second framebuffer descriptor only in dual-panel mode.
1.139 + // Only employ this descriptor in the second DMA channel.
1.140 +
1.141 + _set_descriptor(desc_vaddr[1], get_framebuffer(1, fb_paddr),
1.142 + get_aligned_size(),
1.143 + desc_paddr + 1,
1.144 + _command_irq(),
1.145 + false);
1.146 +
1.147 + // Flush cached structure data.
1.148 +
1.149 + l4_cache_clean_data((unsigned long) desc_vaddr,
1.150 + (unsigned long) desc_vaddr + get_descriptors_size());
1.151 +
1.152 + // Configure DMA by setting frame descriptor addresses.
1.153 +
1.154 + // Provide the palette descriptor address first, if employed.
1.155 +
1.156 + _regs[Desc_address_0] = (uint32_t) desc_paddr;
1.157 +
1.158 + // Provide a descriptor for the second DMA channel, providing foreground 1.
1.159 +
1.160 + _regs[Desc_address_1] = (uint32_t) (desc_paddr + 1);
1.161 +
1.162 + // Initialise panel-related registers.
1.163 +
1.164 + _init_panel();
1.165 +
1.166 + // Initialise the control and configuration registers.
1.167 + // JZ4780 does not support bpp setting here. Otherwise, this is the same as
1.168 + // with earlier SoCs.
1.169 +
1.170 + _regs[Lcd_control] = _control_panel() | _control_transfer() | _control_irq();
1.171 + _regs[Lcd_config] = _panel->config;
1.172 +
1.173 + // JZ4780-specific configuration.
1.174 + // The RGB control register usage may be superfluous.
1.175 +
1.176 + _regs[Rgb_control] = (1U << Rgb_format_enable) | Rgb_odd_line_rgb | Rgb_even_line_rgb;
1.177 + _regs[Priority_level] = _priority_transfer();
1.178 +
1.179 + // Employ whole image alpha levels by default.
1.180 +
1.181 + _regs[Osd_config] = (1U << Osd_config_enable) |
1.182 + (1U << Osd_config_alpha_enable);
1.183 + _regs[Alpha_levels] = ((255U << Alpha_level_fg1) & Alpha_level_fg1_mask) |
1.184 + ((255U << Alpha_level_fg0) & Alpha_level_fg0_mask);
1.185 +}
1.186 +
1.187 +
1.188 +
1.189 +// C language interface functions.
1.190 +
1.191 +void *
1.192 +jz4780_lcd_init(l4_addr_t lcd_base, struct Jz4740_lcd_panel *panel)
1.193 +{
1.194 + return (void *) new Lcd_jz4780_chip(lcd_base, panel);
1.195 +}