1 /* 2 * Export MIPS Creator CI20 HDMI display operations as a server. 3 * 4 * Copyright (C) 2018, 2020 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/cpm-client.h> 23 #include <l4/devices/hdmi-jz4780.h> 24 #include <l4/devices/lcd-jz4740-config.h> 25 #include <l4/devices/lcd-jz4740-panel.h> 26 #include <l4/devices/panel-loader.h> 27 #include <l4/devices/memory.h> 28 29 #include <l4/cxx/ipc_server> 30 #include <l4/re/env> 31 #include <l4/re/util/object_registry> 32 #include <l4/sys/capability> 33 #include <l4/sys/factory> 34 #include <l4/sys/icu.h> 35 36 #include "display-ops.h" 37 38 /* Virtual addresses for the HDMI register block plus interrupt capability. */ 39 40 static l4_addr_t hdmi_virt_base = 0, hdmi_virt_base_end = 0; 41 static l4_uint32_t hdmi_irq_start, hdmi_irq_end; 42 static L4::Cap<L4::Irq> hdmi_irq; 43 static L4::Cap<L4::Icu> icu; 44 45 /* CPM device abstractions. */ 46 47 static Hdmi_jz4780_chip *hdmi = 0; 48 static L4::Cap<Cpm_device_interface> cpm_device; 49 50 51 52 static int setup_memory(void) 53 { 54 if (get_memory("jz4780-hdmi", &hdmi_virt_base, &hdmi_virt_base_end)) 55 return 1; 56 57 if (get_irq("jz4780-hdmi", &hdmi_irq_start, &hdmi_irq_end)) 58 return 1; 59 60 /* Obtain a reference to the CPM device. */ 61 62 cpm_device = L4Re::Env::env()->get_cap<Cpm_device_interface>("cpm"); 63 if (!cpm_device.is_valid()) return 1; 64 65 /* Start the HDMI peripheral. */ 66 67 cpm_device->stop_hdmi(); 68 cpm_device->set_hdmi_frequency(27000000); 69 cpm_device->start_hdmi(); 70 71 /* Load the panel data from the configured library. */ 72 73 struct Jz4740_lcd_panel *panel = (struct Jz4740_lcd_panel *) load_panel(); 74 if (!panel) return 1; 75 76 /* Obtain access to the HDMI interrupt using the ICU. */ 77 78 icu = L4Re::Env::env()->get_cap<L4::Icu>("icu"); 79 80 hdmi_irq = L4Re::Util::cap_alloc.alloc<L4::Irq>(); 81 L4Re::Env::env()->factory()->create(hdmi_irq); 82 83 if (!hdmi_irq.is_valid() || !icu.is_valid()) return 1; 84 85 /* Bind the IRQ object to the interrupt in this thread. */ 86 87 int err = l4_error(icu->bind(hdmi_irq_start, hdmi_irq)); 88 if (err) return err; 89 90 hdmi_irq->bind_thread(L4Re::Env::env()->main_thread(), 0); 91 92 /* Obtain an abstraction for the HDMI peripheral. */ 93 94 hdmi = new Hdmi_jz4780_chip(hdmi_virt_base, hdmi_virt_base_end, hdmi_irq.cap(), panel); 95 96 return 0; 97 } 98 99 100 101 /* Display device. */ 102 103 class Display_device_server : public L4::Server_object_t<L4::Kobject> 104 { 105 public: 106 /* Dispatch incoming requests. */ 107 108 int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) 109 { 110 l4_msgtag_t tag; 111 112 (void) obj; 113 ios >> tag; 114 115 switch (tag.label()) 116 { 117 case Display_op_disable: 118 disable(); 119 return L4_EOK; 120 121 case Display_op_enable: 122 enable(); 123 return L4_EOK; 124 125 default: 126 return -L4_EBADPROTO; 127 } 128 } 129 130 /* Switch the display off. */ 131 132 void disable(void) 133 { 134 } 135 136 /* Switch the display on. */ 137 138 void enable(void) 139 { 140 uint32_t frequency; 141 142 // NOTE: Should test to see if it is connected. 143 144 if (!cpm_device->get_lcd_pixel_frequency(&frequency)) 145 { 146 hdmi->enable(frequency); 147 } 148 } 149 }; 150 151 static L4Re::Util::Registry_server<> server; 152 153 154 155 int main(void) 156 { 157 if (setup_memory()) return 1; 158 159 /* Initialise and register a new server object. */ 160 161 Display_device_server server_obj; 162 server.registry()->register_obj(&server_obj, "display"); 163 164 /* Enter the IPC server loop. */ 165 166 server.loop(); 167 return 0; 168 }