# HG changeset patch # User Paul Boddie # Date 1526168056 -7200 # Node ID 89a1bc19c1fcfef0d0bf22d37fae9b92c2835b0c Added device libraries and programs, configuration files and examples. Also added an installation script and copyright and licensing information. diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-cpm.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-cpm.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,29 @@ +# this is a configuration to start 'ex_ci20_cpm' + +local L4 = require("L4"); + +local l = L4.default_loader; + +local io_buses = + { + cpm = l:new_channel(); + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + log = { "IO", "y" }, + l4re_dbg = L4.Dbg.Warn, + }, + "rom/io -vvvv rom/hw_devices.io rom/mips-ci20-cpm.io"); + +l:start({ + caps = { + icu = L4.Env.icu, + vbus = io_buses.cpm, + }, + }, + "rom/ex_ci20_cpm"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-cpm.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-cpm.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,11 @@ +-- vi:ft=lua +-- configuration file for io + +local hw = Io.system_bus() + +local bus = Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4780-cpm")); +} + +Io.add_vbus("cpm", bus) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-cpm.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-cpm.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,14 @@ + +modaddr 0x1100000 + +entry mips-ci20-cpm-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-ci20-cpm.cfg +module mips-ci20-cpm.cfg +module mips-ci20-cpm.io +module plat-mips-ci20/hw_devices.io +module l4re +module io +module ned +module ex_ci20_cpm diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-i2c.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-i2c.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,29 @@ +# this is a configuration to start 'ex_ci20_i2c' + +local L4 = require("L4"); + +local l = L4.default_loader; + +local io_buses = + { + i2c = l:new_channel(); + }; + +l:start({ + caps = { + i2c = io_buses.i2c:svr(), + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + log = { "IO", "y" }, + l4re_dbg = L4.Dbg.Warn, + }, + "rom/io -vvvv rom/hw_devices.io rom/mips-ci20-i2c.io"); + +l:start({ + caps = { + icu = L4.Env.icu, + vbus = io_buses.i2c, + }, + }, + "rom/ex_ci20_i2c"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-i2c.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-i2c.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +-- vi:ft=lua +-- configuration file for io + +local hw = Io.system_bus() + +local bus = Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4780-cpm")); + GPIO = wrap(hw:match("jz4780-gpio")); + I2C = wrap(hw:match("jz4780-i2c")); +} + +Io.add_vbus("i2c", bus) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-i2c.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-i2c.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,14 @@ + +modaddr 0x1100000 + +entry mips-ci20-i2c-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-ci20-i2c.cfg +module mips-ci20-i2c.cfg +module mips-ci20-i2c.io +module plat-mips-ci20/hw_devices.io +module l4re +module io +module ned +module ex_ci20_i2c diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-led.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-led.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,29 @@ +# this is a configuration to start 'ex_ci20_leds' + +local L4 = require("L4"); + +local l = L4.default_loader; + +local io_buses = + { + gpio = l:new_channel(); + }; + +l:start({ + caps = { + gpio = io_buses.gpio:svr(), + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + log = { "IO", "y" }, + l4re_dbg = L4.Dbg.Warn, + }, + "rom/io -vvvv rom/hw_devices.io rom/mips-ci20-led.io"); + +l:start({ + caps = { + icu = L4.Env.icu, + vbus = io_buses.gpio, + }, + }, + "rom/ex_ci20_leds"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-led.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-led.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,11 @@ +-- vi:ft=lua +-- configuration file for io + +local hw = Io.system_bus() + +local bus = Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4780-gpio")); +} + +Io.add_vbus("gpio", bus) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-ci20-led.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-ci20-led.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,14 @@ + +modaddr 0x1100000 + +entry mips-ci20-led-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-ci20-led.cfg +module mips-ci20-led.cfg +module mips-ci20-led.io +module plat-mips-ci20/hw_devices.io +module l4re +module io +module ned +module ex_ci20_leds diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-fbdrv.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-fbdrv.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,105 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start the framebuffer driver with supporting devices. +-- The target platform is the Letux 400 notebook computer. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + pwm = l:new_channel(); -- exposes GPIO, PWM + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + pwm = io_buses.pwm:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-letux400-fbdrv.io"); + +-- Expose a PWM peripheral as a device. + +local pwm = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.pwm, + pwm = pwm:svr(), + }, + }, + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters + +-- Expose a PWM backlight device. + +local backlight = l:new_channel(); -- exposes backlight device + +l:startv({ + caps = { + pwm = pwm, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits + +-- Expose a display device for the Letux. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_letux400"); + +-- Expose a panel definition for the Letux. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_letux400"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4730"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-fbdrv.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-fbdrv.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,26 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4730-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) + +Io.add_vbus("pwm", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); + PWM = wrap(hw:match("jz4730-pwm")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-fbdrv.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-fbdrv.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,19 @@ + +modaddr 0x1100000 + +entry mips-letux400-fbdrv-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-letux400-fbdrv.cfg +module mips-letux400-fbdrv.cfg +module mips-letux400-fbdrv.io +module plat-letux400/hw_devices.io +module l4re +module io +module ned +module fb-drv +module dev_pwm_jz4730 +module dev_backlight_pwm +module dev_display_letux400 +module dev_panel_letux400 +module dev_cpm_jz4730 diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-demo.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-demo.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,185 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer between several example programs. +-- These programs show the keypad status and also allow the backlight to be +-- adjusted. The target platform is the Letux 400 notebook computer. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + pwm = l:new_channel(); -- exposes GPIO, PWM + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + pwm = io_buses.pwm:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-letux400-keypad-demo.io"); + +-- Expose a PWM peripheral as a device. + +local pwm = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.pwm, + pwm = pwm:svr(), + }, + }, + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters + +-- Expose a PWM backlight device. + +local backlight = l:new_channel(); -- exposes backlight device + +l:startv({ + caps = { + pwm = pwm, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits + +-- Expose a display device for the Letux. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_letux400"); + +-- Expose a panel definition for the Letux. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_letux400"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4730"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); -- exposes framebuffer + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Expose the keypad matrix. + +local keypad = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.gpio, + keypad = keypad:svr(), + }, + }, + "rom/dev_keypad_letux400"); + +-- Show the keypad matrix. + +l:startv({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=400x220+0+0", "barheight=20"), + keypad = keypad, + }, + }, + "rom/ex_keypad_ds_client", "17", "8"); -- specifying keypad matrix dimensions + +-- Show the physical keypad layout. + +l:start({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=400x220+400+0", "barheight=20"), + keypad = keypad, + }, + }, + "rom/ex_letux400_keypad_physical"); + +-- Show key event values. + +l:start({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=400x220+0+240", "barheight=20"), + keypad = keypad, + }, + }, + "rom/ex_letux400_keypad_driver"); + +-- Show key strings. + +l:startv({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=400x220+400+240", "barheight=20"), + keypad = keypad, + }, + }, + "rom/ex_letux400_keypad_driver", "chars"); + +-- Control the backlight using the keyboard. + +l:start({ + caps = { + backlight = backlight, + keypad = keypad, + }, + }, + "rom/ex_letux400_backlight"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-demo.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-demo.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,26 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4730-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) + +Io.add_vbus("pwm", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); + PWM = wrap(hw:match("jz4730-pwm")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-demo.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-demo.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,25 @@ + +modaddr 0x1100000 + +entry mips-letux400-keypad-demo-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-letux400-keypad-demo.cfg +module mips-letux400-keypad-demo.cfg +module mips-letux400-keypad-demo.io +module plat-letux400/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_pwm_jz4730 +module dev_backlight_pwm +module dev_display_letux400 +module dev_panel_letux400 +module dev_cpm_jz4730 +module dev_keypad_letux400 +module ex_letux400_keypad_driver +module ex_keypad_ds_client +module ex_letux400_backlight +module ex_letux400_keypad_physical diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-driver.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-driver.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,145 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer showing only a single program. +-- This example shows the key values produced by the keypad input driver. +-- The target platform is the Letux 400 notebook computer. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + pwm = l:new_channel(); -- exposes GPIO, PWM + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + pwm = io_buses.pwm:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-letux400-keypad-driver.io"); + +-- Expose a PWM peripheral as a device. + +local pwm = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.pwm, + pwm = pwm:svr(), + }, + }, + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters + +-- Expose a PWM backlight device. + +local backlight = l:new_channel(); -- exposes backlight device + +l:startv({ + caps = { + pwm = pwm, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits + +-- Expose a display device for the Letux. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_letux400"); + +-- Expose a panel definition for the Letux. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_letux400"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4730"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Expose the keypad matrix. + +local keypad = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.gpio, + keypad = keypad:svr(), + }, + }, + "rom/dev_keypad_letux400"); + +-- Show key event values. + +l:start({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=800x460+0+0", "barheight=20"), + keypad = keypad, + }, + }, + "rom/ex_letux400_keypad_driver"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-driver.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-driver.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,26 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4730-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) + +Io.add_vbus("pwm", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); + PWM = wrap(hw:match("jz4730-pwm")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-driver.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-driver.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,22 @@ + +modaddr 0x1100000 + +entry mips-letux400-keypad-driver-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-letux400-keypad-driver.cfg +module mips-letux400-keypad-driver.cfg +module mips-letux400-keypad-driver.io +module plat-letux400/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_pwm_jz4730 +module dev_backlight_pwm +module dev_display_letux400 +module dev_panel_letux400 +module dev_cpm_jz4730 +module dev_keypad_letux400 +module ex_letux400_keypad_driver diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-ds.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-ds.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,146 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer showing only a single program. +-- This example shows the keypad status as read from a memory region exported +-- by a separate server that reads the matrix itself. +-- The target platform is the Letux 400 notebook computer. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + pwm = l:new_channel(); -- exposes GPIO, PWM + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + pwm = io_buses.pwm:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-letux400-keypad-ds.io"); + +-- Expose a PWM peripheral as a device. + +local pwm = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.pwm, + pwm = pwm:svr(), + }, + }, + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters + +-- Expose a PWM backlight device. + +local backlight = l:new_channel(); -- exposes backlight device + +l:startv({ + caps = { + pwm = pwm, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits + +-- Expose a display device for the Letux. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_letux400"); + +-- Expose a panel definition for the Letux. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_letux400"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4730"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Expose the keypad matrix. + +local keypad = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.gpio, + keypad = keypad:svr(), + }, + }, + "rom/dev_keypad_letux400"); + +-- Show the keypad matrix. + +l:startv({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=800x460+0+0", "barheight=20"), + keypad = keypad, + }, + }, + "rom/ex_keypad_ds_client", "17", "8"); -- specifying keypad matrix dimensions diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-ds.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-ds.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,26 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4730-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) + +Io.add_vbus("pwm", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); + PWM = wrap(hw:match("jz4730-pwm")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad-ds.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad-ds.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,22 @@ + +modaddr 0x1100000 + +entry mips-letux400-keypad-ds-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-letux400-keypad-ds.cfg +module mips-letux400-keypad-ds.cfg +module mips-letux400-keypad-ds.io +module plat-letux400/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_pwm_jz4730 +module dev_backlight_pwm +module dev_display_letux400 +module dev_panel_letux400 +module dev_cpm_jz4730 +module dev_keypad_letux400 +module ex_keypad_ds_client diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,133 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer showing only a single program. +-- This example shows the keypad status as read from the matrix itself. +-- The target platform is the Letux 400 notebook computer. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + pwm = l:new_channel(); -- exposes GPIO, PWM + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + pwm = io_buses.pwm:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-letux400-keypad.io"); + +-- Expose a PWM peripheral as a device. + +local pwm = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.pwm, + pwm = pwm:svr(), + }, + }, + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters + +-- Expose a PWM backlight device. + +local backlight = l:new_channel(); -- exposes backlight device + +l:startv({ + caps = { + pwm = pwm, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits + +-- Expose a display device for the Letux. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_letux400"); + +-- Expose a panel definition for the Letux. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_letux400"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4730"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Show the keypad status. + +l:start({ + caps = { + vbus = io_buses.gpio, + fb = mag_caps.svc:create(L4.Proto.Goos, "g=800x460+0+0", "barheight=20"), + }, + }, + "rom/ex_letux400_keypad"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,26 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4730-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) + +Io.add_vbus("pwm", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); + PWM = wrap(hw:match("jz4730-pwm")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-keypad.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-keypad.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,38 @@ + +modaddr 0x1100000 + +entry mips-letux400-keypad-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-letux400-keypad.cfg +module mips-letux400-keypad.cfg +module mips-letux400-keypad.io +module plat-letux400/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_pwm_jz4730 +module dev_backlight_pwm +module dev_display_letux400 +module dev_panel_letux400 +module dev_cpm_jz4730 +module ex_letux400_keypad +module lib4re-c.so +module lib4re-c-util.so +module lib4re.so +module lib4re-util.so +module libc_be_l4refile.so +module libc_be_l4re.so +module libc_be_socket_noop.so +module libc_support_misc.so +module libdl.so +module libio-io.so +module libio-vbus.so +module libl4sys.so +module libl4util.so +module libld-l4.so +module libpthread.so +module libsupc++.so +module libuc_c.so diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-lcd-driver.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-lcd-driver.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,102 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Test LCD driver code. The target platform is the Letux 400 notebook computer. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + pwm = l:new_channel(); -- exposes GPIO, PWM + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + pwm = io_buses.pwm:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-letux400-lcd-driver.io"); + +-- Expose a PWM peripheral as a device. + +local pwm = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.pwm, + pwm = pwm:svr(), + }, + }, + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters + +-- Expose a PWM backlight device. + +local backlight = l:new_channel(); -- exposes backlight device + +l:startv({ + caps = { + pwm = pwm, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits + +-- Expose a display device for the Letux. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_letux400"); + +-- Expose a panel definition for the Letux. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_letux400"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4730"); + +-- Start and demonstrate the LCD driver. + +l:start({ + caps = { + icu = L4.Env.icu, + vbus = io_buses.lcd, + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/ex_jz4740_lcd_driver"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-lcd-driver.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-lcd-driver.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,26 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4730-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) + +Io.add_vbus("pwm", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); + PWM = wrap(hw:match("jz4730-pwm")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-lcd-driver.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-lcd-driver.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,19 @@ + +modaddr 0x1100000 + +entry mips-letux400-lcd-driver-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-letux400-lcd-driver.cfg +module mips-letux400-lcd-driver.cfg +module mips-letux400-lcd-driver.io +module plat-letux400/hw_devices.io +module l4re +module io +module ned +module dev_pwm_jz4730 +module dev_backlight_pwm +module dev_display_letux400 +module dev_panel_letux400 +module dev_cpm_jz4730 +module ex_jz4740_lcd_driver diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-led.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-led.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,30 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Test the keyboard LEDs via the GPIO peripheral. +-- The target platform is the Letux 400 notebook computer. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + devices = l:new_channel(); -- exposes GPIO, PWM + }; + +l:start({ + caps = { + devices = io_buses.devices:svr(), + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-letux400-led.io"); + +l:start({ + caps = { + vbus = io_buses.devices, + }, + }, + "rom/ex_letux400_leds"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-led.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-led.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,11 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("devices", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); + PWM = wrap(hw:match("jz4730-pwm")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-led.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-led.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,14 @@ + +modaddr 0x1100000 + +entry mips-letux400-led-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-letux400-led.cfg +module mips-letux400-led.cfg +module mips-letux400-led.io +module plat-letux400/hw_devices.io +module l4re +module io +module ned +module ex_letux400_leds diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-spectrum.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-spectrum.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,132 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer showing only a single program. +-- This example shows an animation showing off a spectrum of colours. +-- The target platform is the Letux 400 notebook computer. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + pwm = l:new_channel(); -- exposes GPIO, PWM + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + pwm = io_buses.pwm:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-letux400-spectrum.io"); + +-- Expose a PWM peripheral as a device. + +local pwm = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.pwm, + pwm = pwm:svr(), + }, + }, + "rom/dev_pwm_jz4730", "0", "250", "299", "47"); -- specifying peripheral number, parameters + +-- Expose a PWM backlight device. + +local backlight = l:new_channel(); -- exposes backlight device + +l:startv({ + caps = { + pwm = pwm, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_pwm", "0", "300"); -- specifying limits + +-- Expose a display device for the Letux. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_letux400"); + +-- Expose a panel definition for the Letux. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_letux400"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4730"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Show the spectrum example. + +l:start({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=800x460", "barheight=20"), + }, + }, + "rom/ex_fb_spectrum_cc"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-spectrum.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-spectrum.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,26 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4730-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) + +Io.add_vbus("pwm", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4730-gpio")); + PWM = wrap(hw:match("jz4730-pwm")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-letux400-spectrum.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-letux400-spectrum.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,21 @@ + +modaddr 0x1100000 + +entry mips-letux400-spectrum-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-letux400-spectrum.cfg +module mips-letux400-spectrum.cfg +module mips-letux400-spectrum.io +module plat-letux400/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_pwm_jz4730 +module dev_backlight_pwm +module dev_display_letux400 +module dev_panel_letux400 +module dev_cpm_jz4730 +module ex_fb_spectrum_cc diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-fbdrv.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-fbdrv.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,103 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start the framebuffer driver with supporting devices. +-- The target platform is the Ben NanoNote. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-qi_lb60-fbdrv.io"); + +-- Expose a SPI peripheral as a device. + +local spi = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.gpio, + spi = spi:svr(), + }, + }, + "rom/dev_spi_jz4740", "C23", "C22", "C21"); -- specifying clock, data, enable pin details + +-- Expose a SPI backlight device for the Ben. + +local backlight = l:new_channel(); -- exposes backlight device + +l:start({ + caps = { + spi = spi, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_spi_qi_lb60"); + +-- Expose a display device for the Ben. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_qi_lb60"); + +-- Expose a panel definition for the Ben. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_qi_lb60"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4740"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-fbdrv.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-fbdrv.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,20 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4740-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4740-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-fbdrv.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-fbdrv.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,19 @@ + +modaddr 0x1100000 + +entry mips-qi_lb60-fbdrv-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-qi_lb60-fbdrv.cfg +module mips-qi_lb60-fbdrv.cfg +module mips-qi_lb60-fbdrv.io +module plat-qi_lb60/hw_devices.io +module l4re +module io +module ned +module fb-drv +module dev_spi_jz4740 +module dev_backlight_spi_qi_lb60 +module dev_display_qi_lb60 +module dev_panel_qi_lb60 +module dev_cpm_jz4740 diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-demo.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-demo.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,183 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer between several example programs. +-- These programs show the keypad status and also allow the backlight to be +-- adjusted. The target platform is the Ben NanoNote. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-qi_lb60-keypad-demo.io"); + +-- Expose a SPI peripheral as a device. + +local spi = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.gpio, + spi = spi:svr(), + }, + }, + "rom/dev_spi_jz4740", "C23", "C22", "C21"); -- specifying clock, data, enable pin details + +-- Expose a SPI backlight device for the Ben. + +local backlight = l:new_channel(); -- exposes backlight device + +l:start({ + caps = { + spi = spi, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_spi_qi_lb60"); + +-- Expose a display device for the Ben. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_qi_lb60"); + +-- Expose a panel definition for the Ben. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_qi_lb60"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4740"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Expose the keypad matrix. + +local keypad = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.gpio, + keypad = keypad:svr(), + }, + }, + "rom/dev_keypad_qi_lb60"); + +-- Show the keypad matrix. + +l:startv({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=160x110+0+0", "barheight=10"), + keypad = keypad, + }, + }, + "rom/ex_keypad_ds_client", "8", "8"); -- specifying keypad matrix dimensions + +-- Show the physical keypad layout. + +l:start({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=160x110+160+0", "barheight=10"), + keypad = keypad, + }, + }, + "rom/ex_qi_lb60_keypad_physical"); + +-- Show key event values. + +l:start({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=160x110+0+120", "barheight=10"), + keypad = keypad, + }, + }, + "rom/ex_qi_lb60_keypad_driver"); + +-- Show key strings. + +l:startv({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=160x110+160+120", "barheight=10"), + keypad = keypad, + }, + }, + "rom/ex_qi_lb60_keypad_driver", "chars"); + +-- Control the backlight using the keyboard. + +l:start({ + caps = { + backlight = backlight, + keypad = keypad, + }, + }, + "rom/ex_qi_lb60_backlight"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-demo.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-demo.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,20 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4740-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4740-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-demo.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-demo.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,25 @@ + +modaddr 0x1100000 + +entry mips-qi_lb60-keypad-demo-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-qi_lb60-keypad-demo.cfg +module mips-qi_lb60-keypad-demo.cfg +module mips-qi_lb60-keypad-demo.io +module plat-qi_lb60/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_spi_jz4740 +module dev_backlight_spi_qi_lb60 +module dev_display_qi_lb60 +module dev_panel_qi_lb60 +module dev_cpm_jz4740 +module dev_keypad_qi_lb60 +module ex_qi_lb60_keypad_driver +module ex_keypad_ds_client +module ex_qi_lb60_keypad_physical +module ex_qi_lb60_backlight diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-driver.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-driver.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,143 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer showing only a single program. +-- This example shows the key values produced by the keypad input driver. +-- The target platform is the Ben NanoNote. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-qi_lb60-keypad-driver.io"); + +-- Expose a SPI peripheral as a device. + +local spi = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.gpio, + spi = spi:svr(), + }, + }, + "rom/dev_spi_jz4740", "C23", "C22", "C21"); -- specifying clock, data, enable pin details + +-- Expose a SPI backlight device for the Ben. + +local backlight = l:new_channel(); -- exposes backlight device + +l:start({ + caps = { + spi = spi, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_spi_qi_lb60"); + +-- Expose a display device for the Ben. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_qi_lb60"); + +-- Expose a panel definition for the Ben. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_qi_lb60"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4740"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Expose the keypad matrix. + +local keypad = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.gpio, + keypad = keypad:svr(), + }, + }, + "rom/dev_keypad_qi_lb60"); + +-- Show key event values. + +l:startv({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=320x230+0+0", "barheight=10"), + keypad = keypad, + }, + }, + "rom/ex_qi_lb60_keypad_driver"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-driver.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-driver.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,20 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4740-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4740-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-driver.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-driver.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,22 @@ + +modaddr 0x1100000 + +entry mips-qi_lb60-keypad-driver-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-qi_lb60-keypad-driver.cfg +module mips-qi_lb60-keypad-driver.cfg +module mips-qi_lb60-keypad-driver.io +module plat-qi_lb60/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_spi_jz4740 +module dev_backlight_spi_qi_lb60 +module dev_display_qi_lb60 +module dev_panel_qi_lb60 +module dev_cpm_jz4740 +module dev_keypad_qi_lb60 +module ex_qi_lb60_keypad_driver diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-ds.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-ds.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,144 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer showing only a single program. +-- This example shows the keypad status as read from a memory region exported +-- by a separate server that reads the matrix itself. +-- The target platform is the Ben NanoNote. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-qi_lb60-keypad-ds.io"); + +-- Expose a SPI peripheral as a device. + +local spi = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.gpio, + spi = spi:svr(), + }, + }, + "rom/dev_spi_jz4740", "C23", "C22", "C21"); -- specifying clock, data, enable pin details + +-- Expose a SPI backlight device for the Ben. + +local backlight = l:new_channel(); -- exposes backlight device + +l:start({ + caps = { + spi = spi, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_spi_qi_lb60"); + +-- Expose a display device for the Ben. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_qi_lb60"); + +-- Expose a panel definition for the Ben. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_qi_lb60"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4740"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Expose the keypad matrix. + +local keypad = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.gpio, + keypad = keypad:svr(), + }, + }, + "rom/dev_keypad_qi_lb60"); + +-- Show the keypad matrix. + +l:startv({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=320x230+0+0", "barheight=10"), + keypad = keypad, + }, + }, + "rom/ex_keypad_ds_client", "8", "8"); -- specifying keypad matrix dimensions diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-ds.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-ds.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,20 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4740-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4740-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad-ds.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad-ds.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,22 @@ + +modaddr 0x1100000 + +entry mips-qi_lb60-keypad-ds-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-qi_lb60-keypad-ds.cfg +module mips-qi_lb60-keypad-ds.cfg +module mips-qi_lb60-keypad-ds.io +module plat-qi_lb60/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_spi_jz4740 +module dev_backlight_spi_qi_lb60 +module dev_display_qi_lb60 +module dev_panel_qi_lb60 +module dev_cpm_jz4740 +module dev_keypad_qi_lb60 +module ex_keypad_ds_client diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,131 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer showing only a single program. +-- This example shows the keypad status as read from the matrix itself. +-- The target platform is the Ben NanoNote. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-qi_lb60-keypad.io"); + +-- Expose a SPI peripheral as a device. + +local spi = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.gpio, + spi = spi:svr(), + }, + }, + "rom/dev_spi_jz4740", "C23", "C22", "C21"); -- specifying clock, data, enable pin details + +-- Expose a SPI backlight device for the Ben. + +local backlight = l:new_channel(); -- exposes backlight device + +l:start({ + caps = { + spi = spi, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_spi_qi_lb60"); + +-- Expose a display device for the Ben. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_qi_lb60"); + +-- Expose a panel definition for the Ben. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_qi_lb60"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4740"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Show the keypad status. + +l:start({ + caps = { + vbus = io_buses.gpio, + fb = mag_caps.svc:create(L4.Proto.Goos, "g=320x230+0+0", "barheight=10"), + }, + }, + "rom/ex_qi_lb60_keypad"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,20 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4740-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4740-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-keypad.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-keypad.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,21 @@ + +modaddr 0x1100000 + +entry mips-qi_lb60-keypad-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-qi_lb60-keypad.cfg +module mips-qi_lb60-keypad.cfg +module mips-qi_lb60-keypad.io +module plat-qi_lb60/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_spi_jz4740 +module dev_backlight_spi_qi_lb60 +module dev_display_qi_lb60 +module dev_panel_qi_lb60 +module dev_cpm_jz4740 +module ex_qi_lb60_keypad diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-lcd-driver.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-lcd-driver.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,100 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Test LCD driver code. The target platform is the Ben NanoNote. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-qi_lb60-lcd-driver.io"); + +-- Expose a SPI peripheral as a device. + +local spi = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.gpio, + spi = spi:svr(), + }, + }, + "rom/dev_spi_jz4740", "C23", "C22", "C21"); -- specifying clock, data, enable pin details + +-- Expose a SPI backlight device for the Ben. + +local backlight = l:new_channel(); -- exposes backlight device + +l:start({ + caps = { + spi = spi, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_spi_qi_lb60"); + +-- Expose a display device for the Ben. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_qi_lb60"); + +-- Expose a panel definition for the Ben. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_qi_lb60"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4740"); + +-- Start and demonstrate the LCD driver. + +l:start({ + caps = { + icu = L4.Env.icu, + vbus = io_buses.lcd, + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/ex_jz4740_lcd_driver"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-lcd-driver.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-lcd-driver.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,20 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4740-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4740-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-lcd-driver.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-lcd-driver.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,19 @@ + +modaddr 0x1100000 + +entry mips-qi_lb60-lcd-driver-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-qi_lb60-lcd-driver.cfg +module mips-qi_lb60-lcd-driver.cfg +module mips-qi_lb60-lcd-driver.io +module plat-qi_lb60/hw_devices.io +module l4re +module io +module ned +module dev_spi_jz4740 +module dev_backlight_spi_qi_lb60 +module dev_display_qi_lb60 +module dev_panel_qi_lb60 +module dev_cpm_jz4740 +module ex_jz4740_lcd_driver diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-lcd.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-lcd.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,30 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Test LCD peripheral. The target platform is the Ben NanoNote. + +local L4 = require("L4"); + +local l = L4.default_loader; + +local io_buses = { + devices = l:new_channel(); -- exposes CPM, GPIO, LCD + }; + +l:start({ + caps = { + devices = io_buses.devices:svr(), + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + log = { "IO", "y" }, + l4re_dbg = L4.Dbg.Warn, + }, + "rom/io -vvvv rom/hw_devices.io rom/mips-qi_lb60-lcd.io"); + +l:start({ + caps = { + icu = L4.Env.icu, + vbus = io_buses.devices, + }, + }, + "rom/ex_qi_lb60_lcd"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-lcd.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-lcd.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,12 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("devices", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4740-cpm")); + GPIO = wrap(hw:match("jz4740-gpio")); + LCD = wrap(hw:match("jz4740-lcd")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-lcd.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-lcd.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,14 @@ + +modaddr 0x1100000 + +entry mips-qi_lb60-lcd-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-qi_lb60-lcd.cfg +module mips-qi_lb60-lcd.cfg +module mips-qi_lb60-lcd.io +module plat-qi_lb60/hw_devices.io +module l4re +module io +module ned +module ex_qi_lb60_lcd diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-spectrum.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-spectrum.cfg Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,130 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Start Mag to multiplex the framebuffer showing only a single program. +-- This example shows an animation showing off a spectrum of colours. +-- The target platform is the Ben NanoNote. + +local L4 = require("L4"); + +local l = L4.default_loader; + +-- Define general access to peripherals. + +local io_buses = { + cpm = l:new_channel(); + gpio = l:new_channel(); + lcd = l:new_channel(); + }; + +l:start({ + caps = { + cpm = io_buses.cpm:svr(), + gpio = io_buses.gpio:svr(), + lcd = io_buses.lcd:svr(), + + icu = L4.Env.icu, + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), + }, + }, + "rom/io rom/hw_devices.io rom/mips-qi_lb60-spectrum.io"); + +-- Expose a SPI peripheral as a device. + +local spi = l:new_channel(); + +l:startv({ + caps = { + vbus = io_buses.gpio, + spi = spi:svr(), + }, + }, + "rom/dev_spi_jz4740", "C23", "C22", "C21"); -- specifying clock, data, enable pin details + +-- Expose a SPI backlight device for the Ben. + +local backlight = l:new_channel(); -- exposes backlight device + +l:start({ + caps = { + spi = spi, + backlight = backlight:svr(), + }, + }, + "rom/dev_backlight_spi_qi_lb60"); + +-- Expose a display device for the Ben. + +local display = l:new_channel(); -- exposes display device + +l:start({ + caps = { + backlight = backlight, + display = display:svr(), + vbus = io_buses.gpio, + }, + }, + "rom/dev_display_qi_lb60"); + +-- Expose a panel definition for the Ben. + +local panel = l:new_channel(); -- exposes panel + +l:start({ + caps = { + panel = panel:svr(), + }, + }, + "rom/dev_panel_qi_lb60"); + +-- Expose the CPM peripheral. + +local cpm = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.cpm, + cpm = cpm:svr(), + }, + }, + "rom/dev_cpm_jz4740"); + +-- Expose a framebuffer device. + +local fbdrv_fb = l:new_channel(); + +l:start({ + caps = { + vbus = io_buses.lcd, + fb = fbdrv_fb:svr(), + cpm = cpm, + display = display, -- needed by LCD driver + panel = panel, + }, + }, + "rom/fb-drv"); + +-- Multiplex the framebuffer. + +local mag_caps = { + mag = l:new_channel(), + svc = l:new_channel(), + }; + +l:start({ + caps = { + vbus = io_buses.gpio, -- needed by input driver + fb = fbdrv_fb, + mag = mag_caps.mag:svr(), + svc = mag_caps.svc:svr(), + }, + }, + "rom/mag"); + +-- Show the spectrum example. + +l:start({ + caps = { + fb = mag_caps.svc:create(L4.Proto.Goos, "g=320x230", "barheight=10"), + }, + }, + "rom/ex_fb_spectrum_cc"); diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-spectrum.io --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-spectrum.io Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,20 @@ +-- vim: ft=lua ts=2 et sw=2 + +-- Configuration file for Io. + +local hw = Io.system_bus() + +Io.add_vbus("cpm", Io.Vi.System_bus +{ + CPM = wrap(hw:match("jz4740-cpm")); +}) + +Io.add_vbus("gpio", Io.Vi.System_bus +{ + GPIO = wrap(hw:match("jz4740-gpio")); +}) + +Io.add_vbus("lcd", Io.Vi.System_bus +{ + LCD = wrap(hw:match("jz4740-lcd")); +}) diff -r 000000000000 -r 89a1bc19c1fc conf/landfall-examples/mips-qi_lb60-spectrum.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/landfall-examples/mips-qi_lb60-spectrum.list Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,21 @@ + +modaddr 0x1100000 + +entry mips-qi_lb60-spectrum-example +bootstrap bootstrap -serial +kernel fiasco -serial_esc +roottask moe rom/mips-qi_lb60-spectrum.cfg +module mips-qi_lb60-spectrum.cfg +module mips-qi_lb60-spectrum.io +module plat-qi_lb60/hw_devices.io +module l4re +module io +module ned +module fb-drv +module mag +module dev_spi_jz4740 +module dev_backlight_spi_qi_lb60 +module dev_display_qi_lb60 +module dev_panel_qi_lb60 +module dev_cpm_jz4740 +module ex_fb_spectrum_cc diff -r 000000000000 -r 89a1bc19c1fc docs/COPYING-GPL-2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/COPYING-GPL-2 Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,1 @@ +LICENCE.txt \ No newline at end of file diff -r 000000000000 -r 89a1bc19c1fc docs/COPYING.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/COPYING.txt Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,79 @@ +Licence Agreement +----------------- + +All original work in this distribution is covered by the following +copyright and licensing information: + +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie + +This software is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +This software is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public +License along with this library; see the file LICENCE.txt +If not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + + +Other code has been incorporated into this distribution and is +covered by the following copyrights: + +pkg/devices/lib/common/include: + + (c) 2014 Alexander Warg + +pkg/landfall-examples/qi_lb60_lcd: + + Copyright (C) 2001 Wolfgang Denk, DENX Software Engineering, wd@denx.de. + Copyright (C) 2005-2007, Ingenic Semiconductor Inc. + Copyright (C) 2009 Qi Hardware Inc. + Copyright (C) Xiangfu Liu + +Note that due to the incorporation of code from L4Re, the following +files are actually licensed under the GPL version 2 only: + +pkg/devices/lib/common/include/hw_mmio_register_block.h +pkg/devices/lib/common/include/hw_register_block.h +pkg/devices/lib/gpio/include/gpio.h +pkg/devices/lib/gpio/include/gpio-jz4730.h +pkg/devices/lib/gpio/include/gpio-jz4740.h +pkg/devices/lib/gpio/include/gpio-jz4780.h +pkg/devices/lib/gpio/src/jz4730.cc +pkg/devices/lib/gpio/src/jz4740.cc +pkg/devices/lib/gpio/src/jz4780.cc + +No clear copyright statements are provided in the L4Re distribution +for such files. + + + +Font definitions and licence (see unifont.tff for bitmap data +derived from GNU Unifont's unifont.hex file): + +Copyright (C) 1998-2003 Roman Czyborra (http://czyborra.com/) + + All glyphs are released under the GNU General Public License + (GPL) version 2 or (at your option) a later version, with the + GNU font embedding exception: + + ** GPL v2.0 license with font embedding exception: + + As a special exception, if you create a document which + uses this font, and embed this font or unaltered portions + of this font into the document, this font does not by + itself cause the resulting document to be covered by + the GNU General Public License. This exception does not + however invalidate any other reasons why the document + might be covered by the GNU General Public License. + If you modify this font, you may extend this exception + to your version of the font, but you are not obligated + to do so. If you do not wish to do so, delete this + exception statement from your version. diff -r 000000000000 -r 89a1bc19c1fc docs/LICENCE.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/LICENCE.txt Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/Control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/Control Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,24 @@ +provides: libdrivers-common libdrivers-cpm libdrivers-gpio libdrivers-i2c libdrivers-pwm +provides: libdrivers-keypad libdrivers-keypad-letux400 libdrivers-keypad-qi_lb60 +provides: libdrivers-lcd-jz4740 +provides: devices-backlight-pwm libdevice-backlight-client +provides: devices-cpm-jz4730 devices-cpm-jz4740 devices-cpm-jz4780 +provides: libdevice-cpm-client libdevice-cpm-ops +provides: libdevice-cpm-server +provides: devices-display-letux400 devices-display-qi_lb60 +provides: libdevice-display-client libdevice-display-ops +provides: devices-fb-jz4740 +provides: libdevice-fb-client libdevice-fb-ops +provides: libdevice-fb-lcd libdevice-fb-server +provides: libdevice-input-keypad +provides: devices-keypad-letux400 devices-keypad-qi_lb60 +provides: libdevice-keypad-client libdevice-keypad-ops +provides: libdevice-keypad-server +provides: libdevice-lcd libdevice-lcd-jz4740 +provides: devices-panel-letux400 devices-panel-qi_lb60 +provides: libdevice-panel-client libdevice-panel-ops +provides: devices-pwm-jz4730 libdevice-pwm-client +provides: devices-spi-jz4740 libdevice-spi-client +provides: libdevice-util +requires: libc l4re_c libio +Maintainer: paul@boddie.org.uk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,21 @@ +PKGDIR = . +L4DIR ?= $(PKGDIR)/../.. + +TARGET = backlight cpm display fb input keypad lcd lib panel pwm spi util + +include $(L4DIR)/mk/subdir.mk + +# Internal dependencies. +# lib provides driver libraries +# util provides peripheral memory access + +backlight: pwm spi +cpm: lib util +display: backlight lib util +fb: lcd lib util +input: keypad lib +keypad: lib util +lcd: display panel lib util +panel: lib +pwm: lib util +spi: lib util diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/include/backlight-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/include/backlight-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,39 @@ +/* + * Backlight client to access backlight servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include "backlight-ops.h" + +class Backlight_device_interface : public L4::Kobject_t +{ + L4_KOBJECT(Backlight_device_interface) + +public: + int disable() throw(); + int enable() throw(); + int set_brightness(int level) throw(); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/include/backlight-ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/include/backlight-ops.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,24 @@ +/* + * Backlight server operations. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum { Backlight_op_disable, Backlight_op_enable, Backlight_op_set_brightness }; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := client pwm spi-qi_lb60 + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/src/client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/src/client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_backlight_client.o.a +PC_FILENAME := libdevice-backlight-client + +SRC_CC := backlight-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/backlight/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/src/client/backlight-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/src/client/backlight-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,50 @@ +/* + * Backlight client to access backlight servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "backlight-client.h" + +int +Backlight_device_interface::disable() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Backlight_op_disable)); +} + +int +Backlight_device_interface::enable() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Backlight_op_enable)); +} + +int +Backlight_device_interface::set_brightness(int level) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + s << level; + return l4_error(s.call(cap(), Backlight_op_set_brightness)); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/src/pwm/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/src/pwm/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_backlight_pwm +PC_FILENAME := devices-backlight-pwm + +SRC_CC := backlight-pwm.cc + +PRIVATE_INCDIR += $(PKGDIR)/backlight/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-pwm-client + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/src/pwm/backlight-pwm.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/src/pwm/backlight-pwm.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,128 @@ +/* + * Access a PWM server to update a display panel backlight. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include + +#include +#include "backlight-ops.h" + +/* PWM access abstractions. */ + +static L4::Cap pwm_device; + + + +/* Backlight device. */ + +class Backlight_device_server : public L4::Server_object_t +{ + int _min, _max; + +public: + explicit Backlight_device_server(int min, int max) + : _min(min), _max(max) + { + } + + /* Dispatch incoming requests. */ + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) + { + l4_msgtag_t tag; + int arg; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case Backlight_op_disable: + disable(); + return L4_EOK; + + case Backlight_op_enable: + enable(); + return L4_EOK; + + case Backlight_op_set_brightness: + ios >> arg; + set_brightness(arg); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } + } + + void disable() + { + pwm_device->disable(); + } + + void enable() + { + pwm_device->enable(); + } + + /* Use the PWM device to update the backlight level. */ + + void set_brightness(int level) + { + pwm_device->set_duty(level); + } +}; + +static L4Re::Util::Registry_server<> server; + + + +/* Arguments: */ + +int main(int argc, char *argv[]) +{ + int min, max; + + if (argc < 3) + return 1; + + /* Obtain a reference to the PWM device. */ + + pwm_device = L4Re::Env::env()->get_cap("pwm"); + if (!pwm_device.is_valid()) return 1; + + /* Initialise and register a new server object. */ + + min = atoi(argv[1]); + max = atoi(argv[2]); + + Backlight_device_server server_obj(min, max); + server.registry()->register_obj(&server_obj, "backlight"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/src/spi-qi_lb60/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/src/spi-qi_lb60/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_backlight_spi_qi_lb60 +PC_FILENAME := devices-backlight-spi-qi_lb60 + +SRC_CC := backlight-spi-qi_lb60.cc + +PRIVATE_INCDIR += $(PKGDIR)/backlight/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-spi-client + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/backlight/src/spi-qi_lb60/backlight-spi-qi_lb60.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/backlight/src/spi-qi_lb60/backlight-spi-qi_lb60.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,130 @@ +/* + * Access a SPI server to update a display panel backlight. + * This server is specific to the Ben NanoNote. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include + +#include +#include "backlight-ops.h" + +/* SPI access abstractions. */ + +static L4::Cap spi_device; + + + +/* Backlight device. */ + +class Backlight_device_server : public L4::Server_object_t +{ + int _min = 55, _max = 90, _start = 70; + + void set_duty(int level) + { + level = level < _min ? _min : (level > _max ? _max : level); + + /* PWM_DUTY = R05h<5:3> = 5% increments from min to max */ + + int duty = ((level - _min) / 5) << 3; + + spi_device->send(16, 0x0516 | duty); /* R05h: GRB=0 (reset); PWM_DUTY=duty; SHDB2=1, SHDB1=1 (power-related); STB=0 (standby) */ + spi_device->send(16, 0x0546 | duty); /* R05h: GRB=1 (normal operation); ... */ + spi_device->send(16, 0x078d); /* R07h: HBLK=141 (horizontal blanking period from start of hsync pulse to data start) */ + spi_device->send(16, 0x1301); /* R13h: IN_SEL=1 (alignment mode) */ + spi_device->send(16, 0x0547 | duty); /* R05h: ...; STB=1 (not standby) */ + } + +public: + /* Dispatch incoming requests. */ + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) + { + l4_msgtag_t tag; + int arg; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case Backlight_op_disable: + disable(); + return L4_EOK; + + case Backlight_op_enable: + enable(); + return L4_EOK; + + case Backlight_op_set_brightness: + ios >> arg; + set_brightness(arg); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } + } + + void disable() + { + spi_device->send(16, 0x055e); + } + + void enable() + { + set_duty(_start); + } + + /* Use the SPI device to update the brightness level. */ + + void set_brightness(int level) + { + level = level < _min ? _min : (level > _max ? _max : level); + spi_device->send(16, 0x0300 | level); /* R03h: brightness */ + } +}; + +static L4Re::Util::Registry_server<> server; + + + +int main(void) +{ + /* Obtain a reference to the SPI device. */ + + spi_device = L4Re::Env::env()->get_cap("spi"); + if (!spi_device.is_valid()) return 1; + + /* Initialise and register a new server object. */ + + Backlight_device_server server_obj; + server.registry()->register_obj(&server_obj, "backlight"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/include/cpm-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/include/cpm-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,40 @@ +/* + * CPM client to access CPM servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include + +class Cpm_device_interface : public L4::Kobject_t +{ + L4_KOBJECT(Cpm_device_interface) + +public: + int set_lcd_frequencies(uint32_t pclk, uint8_t multiplier) throw(); + int start_lcd() throw(); + int stop_lcd() throw(); + int update_output_frequency() throw(); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/include/cpm-ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/include/cpm-ops.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,29 @@ +/* + * CPM server operations. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum { + Cpm_op_set_lcd_frequencies, + Cpm_op_start_lcd, + Cpm_op_stop_lcd, + Cpm_op_update_output_frequency, +}; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/include/cpm-server.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/include/cpm-server.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,49 @@ +/* + * Common CPM server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +#ifdef __cplusplus + +#include +#include +#include + +/* Server object to provide CPM access. */ + +class Cpm_server : public L4::Server_object_t +{ +private: + Cpm_chip *_chip; + +public: + /* Initialise the server with a peripheral reference. */ + + explicit Cpm_server(Cpm_chip *chip) + : _chip(chip) + {} + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,10 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := client jz4730 jz4740 jz4780 server + +include $(L4DIR)/mk/subdir.mk + +jz4730: server +jz4740: server +jz4780: server diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_cpm_client.o.a +PC_FILENAME := libdevice-cpm-client + +SRC_CC := cpm-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/cpm/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/client/cpm-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/client/cpm-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,60 @@ +/* + * CPM client to access CPM servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "cpm-client.h" +#include "cpm-ops.h" + +int +Cpm_device_interface::set_lcd_frequencies(uint32_t pclk, uint8_t multiplier) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + s << pclk << multiplier; + + return l4_error(s.call(cap(), Cpm_op_set_lcd_frequencies)); +} + +int +Cpm_device_interface::start_lcd() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Cpm_op_start_lcd)); +} + +int +Cpm_device_interface::stop_lcd() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Cpm_op_stop_lcd)); +} + +int +Cpm_device_interface::update_output_frequency() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Cpm_op_update_output_frequency)); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/jz4730/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/jz4730/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_cpm_jz4730 +PC_FILENAME := devices-cpm-jz4730 + +SRC_CC := cpm-jz4730.cc + +PRIVATE_INCDIR += $(PKGDIR)/cpm/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-cpm libdevice-cpm-server libdevice-util + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/jz4730/cpm-jz4730.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/jz4730/cpm-jz4730.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,73 @@ +/* + * JZ4730 CPM server. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include "cpm-server.h" + +#include +#include +#include + +#include + +// Virtual addresses for the CPM and LCD register blocks. + +static l4_addr_t cpm_virt_base = 0, cpm_virt_base_end = 0; + + + +// Access to peripheral memory. + +static int setup_memory() +{ + if (get_memory("jz4730-cpm", &cpm_virt_base, &cpm_virt_base_end)) + return 1; + + return 0; +} + + + +static L4Re::Util::Registry_server<> server; + + + +/* Main program. */ + +int main(void) +{ + if (setup_memory()) return 1; + + /* Initialise the CPM abstraction. */ + + Cpm_jz4730_chip cpm_device(cpm_virt_base, 3686400); + + /* Initialise and register a server object. */ + + Cpm_server server_obj(&cpm_device); + server.registry()->register_obj(&server_obj, "cpm"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/jz4740/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/jz4740/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_cpm_jz4740 +PC_FILENAME := devices-cpm-jz4740 + +SRC_CC := cpm-jz4740.cc + +PRIVATE_INCDIR += $(PKGDIR)/cpm/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-cpm libdevice-cpm-server libdevice-util + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/jz4740/cpm-jz4740.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/jz4740/cpm-jz4740.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,73 @@ +/* + * JZ4740 CPM server. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include "cpm-server.h" + +#include +#include +#include + +#include + +// Virtual addresses for the CPM and LCD register blocks. + +static l4_addr_t cpm_virt_base = 0, cpm_virt_base_end = 0; + + + +// Access to peripheral memory. + +static int setup_memory() +{ + if (get_memory("jz4740-cpm", &cpm_virt_base, &cpm_virt_base_end)) + return 1; + + return 0; +} + + + +static L4Re::Util::Registry_server<> server; + + + +/* Main program. */ + +int main(void) +{ + if (setup_memory()) return 1; + + /* Initialise the CPM abstraction. */ + + Cpm_jz4740_chip cpm_device(cpm_virt_base, 12000000); + + /* Initialise and register a server object. */ + + Cpm_server server_obj(&cpm_device); + server.registry()->register_obj(&server_obj, "cpm"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/jz4780/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/jz4780/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_cpm_jz4780 +PC_FILENAME := devices-cpm-jz4780 + +SRC_CC := cpm-jz4780.cc + +PRIVATE_INCDIR += $(PKGDIR)/cpm/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-cpm libdevice-cpm-server libdevice-util + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/jz4780/cpm-jz4780.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/jz4780/cpm-jz4780.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,73 @@ +/* + * JZ4780 CPM server. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include "cpm-server.h" + +#include +#include +#include + +#include + +// Virtual addresses for the CPM and LCD register blocks. + +static l4_addr_t cpm_virt_base = 0, cpm_virt_base_end = 0; + + + +// Access to peripheral memory. + +static int setup_memory() +{ + if (get_memory("jz4780-cpm", &cpm_virt_base, &cpm_virt_base_end)) + return 1; + + return 0; +} + + + +static L4Re::Util::Registry_server<> server; + + + +/* Main program. */ + +int main(void) +{ + if (setup_memory()) return 1; + + /* Initialise the CPM abstraction. */ + + Cpm_jz4780_chip cpm_device(cpm_virt_base, 48000000, 32768); + + /* Initialise and register a server object. */ + + Cpm_server server_obj(&cpm_device); + server.registry()->register_obj(&server_obj, "cpm"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/server/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/server/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_cpm_server.o.a +PC_FILENAME := libdevice-cpm-server + +SRC_CC := cpm-server.cc + +PRIVATE_INCDIR += $(PKGDIR)/cpm/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-cpm + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/cpm/src/server/cpm-server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/cpm/src/server/cpm-server.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,69 @@ +/* + * Common CPM server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "cpm-client.h" +#include "cpm-server.h" +#include "cpm-ops.h" + +#include +#include +#include +#include + +/* Handle invocations. */ + +int +Cpm_server::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) +{ + l4_msgtag_t tag; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case L4::Meta::Protocol: + return L4::Util::handle_meta_request(ios); + + case Cpm_op_set_lcd_frequencies: + uint32_t pclk; + int multiplier; + ios >> pclk; + ios >> multiplier; + _chip->set_lcd_frequencies(pclk, multiplier); + return L4_EOK; + + case Cpm_op_start_lcd: + _chip->start_lcd(); + return L4_EOK; + + case Cpm_op_stop_lcd: + _chip->stop_lcd(); + return L4_EOK; + + case Cpm_op_update_output_frequency: + _chip->update_output_frequency(); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +PC_FILENAME := libdevice-display-ops + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/include/display-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/include/display-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,40 @@ +/* + * Display client to access display servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include "display-ops.h" + +#include + +class Display_device_interface : public L4::Kobject_t +{ + L4_KOBJECT(Display_device_interface) + +public: + int disable() throw(); + int enable() throw(); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/include/display-ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/include/display-ops.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,24 @@ +/* + * Display server operations. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum { Display_op_disable, Display_op_enable }; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := client letux400 qi_lb60 + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/src/client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/src/client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_display_client.o.a +PC_FILENAME := libdevice-display-client + +SRC_CC := display-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/display/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/src/client/display-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/src/client/display-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,44 @@ +/* + * Display client to access display servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "display-client.h" + +#include + +int +Display_device_interface::disable() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Display_op_disable)); +} + +int +Display_device_interface::enable() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Display_op_enable)); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/src/letux400/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/src/letux400/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_display_letux400 +PC_FILENAME := devices-display-letux400 + +SRC_CC := display-letux400.cc + +PRIVATE_INCDIR += $(PKGDIR)/display/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-backlight-client libdrivers-gpio libdevice-util + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/src/letux400/display-letux400.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/src/letux400/display-letux400.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,162 @@ +/* + * Export Letux 400 display operations as a server. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "display-ops.h" + +/* Virtual address for the GPIO register block. */ + +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; + +/* GPIO and backlight device abstractions. */ + +static Gpio_jz4730_chip *gpio_port_b = 0, *gpio_port_c = 0; +static L4::Cap backlight_device; + + + +/* GPIO pin definitions. */ + +enum Jz4730_lcd_gpio_mask +{ + Jz4730_lcd_gpio_func1 = 0xf8ffff00, + Jz4730_lcd_gpio_func2 = 0x07000000, +}; + +enum Jz4730_lcd_gpio +{ + Jz4730_lcd_gpio_led_enable = 28, + Jz4730_lcd_gpio_display_enable = 29, +}; + + + +static int setup_memory(void) +{ + if (get_memory("jz4730-gpio", &gpio_virt_base, &gpio_virt_base_end)) + return 1; + + return 0; +} + + + +/* Display device. */ + +class Display_device_server : public L4::Server_object_t +{ + Pin_slice lcd_mask1 = {.offset=0, .mask=Jz4730_lcd_gpio_func1}; + Pin_slice lcd_mask2 = {.offset=0, .mask=Jz4730_lcd_gpio_func2}; + +public: + explicit Display_device_server() + { + /* Set functions for the LCD pins. */ + + gpio_port_b->multi_config_pad(lcd_mask1, Hw::Gpio_chip::Function_alt, 1); + gpio_port_b->multi_config_pad(lcd_mask2, Hw::Gpio_chip::Function_alt, 2); + + /* Enable LED, disable display. */ + + gpio_port_c->setup(Jz4730_lcd_gpio_led_enable, Hw::Gpio_chip::Output, 1); + gpio_port_c->setup(Jz4730_lcd_gpio_display_enable, Hw::Gpio_chip::Output, 0); + } + + /* Dispatch incoming requests. */ + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) + { + l4_msgtag_t tag; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case Display_op_disable: + disable(); + return L4_EOK; + + case Display_op_enable: + enable(); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } + } + + /* Switch the display off. */ + + void disable(void) + { + gpio_port_c->setup(Jz4730_lcd_gpio_display_enable, Hw::Gpio_chip::Output, 0); + backlight_device->disable(); + } + + /* Switch the display on. */ + + void enable(void) + { + gpio_port_c->setup(Jz4730_lcd_gpio_display_enable, Hw::Gpio_chip::Output, 1); + backlight_device->enable(); + } +}; + +static L4Re::Util::Registry_server<> server; + + + +int main(void) +{ + if (setup_memory()) return 1; + + /* Initialise the GPIO abstractions. */ + + Gpio_jz4730_chip gpb(gpio_virt_base + (1 * 0x30), gpio_virt_base + (2 * 0x30), 32); + Gpio_jz4730_chip gpc(gpio_virt_base + (2 * 0x30), gpio_virt_base + (3 * 0x30), 32); + + gpio_port_b = &gpb; + gpio_port_c = &gpc; + + /* Obtain a reference to the backlight device. */ + + backlight_device = L4Re::Env::env()->get_cap("backlight"); + if (!backlight_device.is_valid()) return 1; + + /* Initialise and register a new server object. */ + + Display_device_server server_obj; + server.registry()->register_obj(&server_obj, "display"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/src/qi_lb60/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/src/qi_lb60/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_display_qi_lb60 +PC_FILENAME := devices-display-qi_lb60 + +SRC_CC := display-qi_lb60.cc + +PRIVATE_INCDIR += $(PKGDIR)/display/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-backlight-client libdrivers-lcd-jz4740 libdrivers-gpio libdevice-util + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/display/src/qi_lb60/display-qi_lb60.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/display/src/qi_lb60/display-qi_lb60.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,153 @@ +/* + * Export Ben NanoNote display operations as a server. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "display-ops.h" + +/* Virtual address for the GPIO register block. */ + +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; + +/* GPIO and backlight device abstractions. */ + +static Gpio_jz4740_chip *gpio_port_c = 0; +static L4::Cap backlight_device; + + + +/* GPIO pin definitions. */ + +enum Jz4740_lcd_gpio_mask +{ + Jz4740_lcd_gpio_d0_d7 = 0xff, +}; + +enum Jz4740_lcd_gpio +{ + Jz4740_lcd_gpio_clk = 18, /* pixel clock */ + Jz4740_lcd_gpio_rs = 19, /* hsync; command/data select */ + Jz4740_lcd_gpio_cs = 20, /* vsync; chip select */ +}; + + + +static int setup_memory(void) +{ + if (get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end)) + return 1; + + return 0; +} + + + +/* Display device. */ + +class Display_device_server : public L4::Server_object_t +{ + Pin_slice slcd8_mask = {.offset=0, .mask=(1 << Jz4740_lcd_gpio_cs) | (1 << Jz4740_lcd_gpio_rs) | + (1 << Jz4740_lcd_gpio_clk) | Jz4740_lcd_gpio_d0_d7}; + +public: + /* Dispatch incoming requests. */ + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) + { + l4_msgtag_t tag; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case Display_op_disable: + disable(); + return L4_EOK; + + case Display_op_enable: + enable(); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } + } + + /* Switch the display off. */ + + void disable(void) + { + /* Configure SLCD8 pins. */ + + gpio_port_c->multi_setup(slcd8_mask, Hw::Gpio_chip::Input, 0); + backlight_device->disable(); + } + + /* Switch the display on. */ + + void enable(void) + { + /* Configure SLCD8 pins. */ + + gpio_port_c->multi_config_pad(slcd8_mask, Hw::Gpio_chip::Function_alt, 0); + backlight_device->enable(); + } +}; + +static L4Re::Util::Registry_server<> server; + + + +int main(void) +{ + if (setup_memory()) return 1; + + /* Initialise the GPIO abstraction. */ + + Gpio_jz4740_chip gpio_port(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32); + + gpio_port_c = &gpio_port; + + /* Obtain a reference to the backlight device. */ + + backlight_device = L4Re::Env::env()->get_cap("backlight"); + if (!backlight_device.is_valid()) return 1; + + /* Initialise and register a new server object. */ + + Display_device_server server_obj; + server.registry()->register_obj(&server_obj, "display"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +PC_FILENAME := libdevice-fb-ops + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/include/fb-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/include/fb-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,41 @@ +/* + * Framebuffer client to access framebuffer servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include +#include +#include + +class Framebuffer_device_interface : public L4::Kobject_t +{ + L4_KOBJECT(Framebuffer_device_interface) + +public: + int get_framebuffer(L4::Cap mem) throw(); + l4_size_t get_framebuffer_size() throw(); + int get_view_info(l4re_video_view_info_t *view_info) throw(); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/include/fb-lcd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/include/fb-lcd.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,50 @@ +/* + * LCD framebuffer server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include "fb-server.h" + +#ifdef __cplusplus + +#include +#include + +class Framebuffer_lcd_server : public Framebuffer_server +{ + Lcd_device *_device; + +public: + explicit Framebuffer_lcd_server(L4::Cap mem, Lcd_device *device) + : Framebuffer_server(mem), _device(device) + { + } + + l4_size_t get_framebuffer_size(); + void get_view_info(l4re_video_view_info_t *view_info); +}; + +#endif + +/* Common initiation method. */ + +int run(void); diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/include/fb-ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/include/fb-ops.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,28 @@ +/* + * Framebuffer server operations. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum { + Framebuffer_op_get_framebuffer, + Framebuffer_op_get_framebuffer_size, + Framebuffer_op_get_view_info, +}; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/include/fb-server.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/include/fb-server.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,54 @@ +/* + * Common framebuffer server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include +#include +#include +#include + +/* Server object to provide framebuffer data access. */ + +class Framebuffer_server : public L4::Server_object_t +{ +private: + L4::Cap _mem; + +public: + /* Initialise the server with a capability referencing the exported memory. */ + + explicit Framebuffer_server(L4::Cap mem) + : _mem(mem) + {} + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios); + + /* Operation methods. */ + + virtual l4_size_t get_framebuffer_size() = 0; + virtual void get_view_info(l4re_video_view_info_t *view_info) = 0; +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,9 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := client jz4740 lcd server + +include $(L4DIR)/mk/subdir.mk + +jz4740: lcd +lcd: server diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_fb_client.o.a +PC_FILENAME := libdevice-fb-client + +SRC_CC := fb-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/fb/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/client/fb-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/client/fb-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,72 @@ +/* + * Framebuffer client to access framebuffer servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "fb-client.h" +#include "fb-ops.h" + +#include +#include + +#include + +int +Framebuffer_device_interface::get_framebuffer(L4::Cap mem) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + /* Send a "receive item" for requesting a capability. */ + + s << L4::Ipc::Small_buf(mem); + + return l4_error(s.call(cap(), Framebuffer_op_get_framebuffer)); +} + +l4_size_t +Framebuffer_device_interface::get_framebuffer_size() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + l4_size_t size; + + /* Return zero on failure. */ + + if (l4_error(s.call(cap(), Framebuffer_op_get_framebuffer_size))) + return 0; + + s >> size; + return size; +} + +int +Framebuffer_device_interface::get_view_info(l4re_video_view_info_t *view_info) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + int err = l4_error(s.call(cap(), Framebuffer_op_get_view_info)); + if (err) return err; + + unsigned long expected = sizeof(*view_info); + unsigned long size = expected; + + s >> L4::Ipc::buf_cp_in((uint8_t *) view_info, expected); + + if (size != expected) return -L4_EIO; + return L4_EOK; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/jz4740/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/jz4740/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_fb_jz4740 +PC_FILENAME := devices-fb-jz4740 + +SRC_CC := fb-jz4740.cc + +PRIVATE_INCDIR += $(PKGDIR)/fb/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-fb-lcd libdevice-lcd-jz4740 + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/jz4740/fb-jz4740.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/jz4740/fb-jz4740.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,29 @@ +/* + * Export the framebuffer for the Ben NanoNote via the "fb" capability. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "fb-lcd.h" + +/* Main program. */ + +int main() +{ + return run(); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/lcd/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/lcd/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_fb_lcd.o.a +PC_FILENAME := libdevice-fb-lcd + +SRC_CC := fb-lcd.cc + +PRIVATE_INCDIR += $(PKGDIR)/fb/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-fb-server libdevice-lcd + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/lcd/fb-lcd.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/lcd/fb-lcd.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,80 @@ +/* + * Export the framebuffer as a data space accessible via the "fb" capability. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include "fb-lcd.h" +#include "fb-server.h" + +#include +#include +#include +#include + + + +// Device-specific methods. + +l4_size_t +Framebuffer_lcd_server::get_framebuffer_size() +{ + return _device->get_framebuffer_size(); +} + +void +Framebuffer_lcd_server::get_view_info(l4re_video_view_info_t *view_info) +{ + _device->get_view_info(view_info); +} + + + +static L4Re::Util::Registry_server<> server; + + + +// Main program. + +int run() +{ + // Obtain the LCD device. + + Lcd_device *lcd_device = Lcd_device::get_device(); + + // Memory allocation capability for the framebuffer data. + + L4::Cap mem = lcd_device->get_framebuffer_cap(); + + if (!mem.is_valid()) return 1; + + // Enable the LCD device. + + lcd_device->enable(); + + // Initialise and register a server object. + + Framebuffer_lcd_server server_obj(mem, lcd_device); + server.registry()->register_obj(&server_obj, "fb"); + + // Enter the IPC server loop. + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/server/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/server/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_fb_server.o.a +PC_FILENAME := libdevice-fb-server + +SRC_CC := fb-server.cc + +PRIVATE_INCDIR += $(PKGDIR)/fb/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/fb/src/server/fb-server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/fb/src/server/fb-server.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,68 @@ +/* + * Common framebuffer server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "fb-client.h" +#include "fb-server.h" +#include "fb-ops.h" + +#include +#include +#include +#include + +#include + +/* Handle invocations. */ + +int +Framebuffer_server::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) +{ + l4_msgtag_t tag; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case L4::Meta::Protocol: + return L4::Util::handle_meta_request(ios); + + case Framebuffer_op_get_framebuffer: + ios << _mem; + return L4_EOK; + + case Framebuffer_op_get_framebuffer_size: + ios << get_framebuffer_size(); + return L4_EOK; + + case Framebuffer_op_get_view_info: + l4re_video_view_info_t view_info; + get_view_info(&view_info); + + /* Serialise the view information structure. */ + + ios << L4::Ipc::buf_cp_out((uint8_t *) &view_info, sizeof(view_info)); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/input/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/input/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/input/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/input/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +PC_FILENAME := libdevice-input-ops + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/input/include/input-keypad-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/input/include/input-keypad-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,108 @@ +/* + * Common keypad client functionality for input event generation. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + +#include +#include + +#include + +#include + +/* Input event and handler. */ + +typedef struct +{ + enum L4Re_events_ev type; + int code; + int value; +} Input_event; + +typedef void (*Input_handler)(Input_event, void *); + + + +#ifdef __cplusplus + +#include +#include + +/* Client object to provide input event access. */ + +class Input_keypad_client +{ + /* Memory and keypad access capabilities. */ + + L4::Cap _mem; + L4::Cap _keypad_server; + + /* Keypad layout details. */ + + Keypad *_keypad; + + /* Keypad memory. */ + + void *_keymem = 0, *_keymem_previous = 0; + + /* Input framework integration. */ + + Input_handler _handler = 0; + + /* Thread details. */ + + pthread_t _pthread; + void *_priv; + + /* Initialisation functions. */ + + void init_memory(); + void init_keypad(); + void init_keypad_data(); + void release_keypad_data(); + + /* Activity methods. */ + + static void *scan_mainloop(void *data); + void scan_keypad(); + +public: + explicit Input_keypad_client(Keypad *keypad) : _keypad(keypad) + { + init_memory(); + init_keypad(); + init_keypad_data(); + } + + ~Input_keypad_client() + { + release_keypad_data(); + } + + /* Thread initialisation. */ + + void attach(Input_handler handler, void *priv); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/input/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/input/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := keypad + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/input/src/keypad/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/input/src/keypad/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libinput_keypad.o.a +PC_FILENAME := libdevice-input-keypad + +SRC_CC := input-keypad-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/input/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-keypad-client libdrivers-keypad + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/input/src/keypad/input-keypad-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/input/src/keypad/input-keypad-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,191 @@ +/* + * Common keypad client functionality for input event generation. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* Obtain a capability for the keypad data. */ + +void +Input_keypad_client::init_memory() +{ + _mem = L4Re::Util::cap_alloc.alloc(); +} + +/* Obtain a reference to the keypad. */ + +void +Input_keypad_client::init_keypad() +{ + _keypad_server = L4Re::Env::env()->get_cap("keypad"); +} + +/* Access the keypad server memory. */ + +void +Input_keypad_client::init_keypad_data() +{ + if (!_mem.is_valid()) + return; + + if (!_keypad_server.is_valid()) + return; + + /* Obtain a reference to the keypad data. */ + + if (_keypad_server->get_keypad_data(_mem)) + return; + + /* Attach the keypad data to a region in this task. */ + + if (L4Re::Env::env()->rm()->attach(&_keymem, _mem->size(), + L4Re::Rm::Search_addr, + L4::Ipc::make_cap_rw(_mem))) + return; + + /* Allocate memory for a copy of the keypad data. */ + + _keymem_previous = malloc(_mem->size()); +} + +/* Release capabilities and the memory for a copy of the keypad data. */ + +void +Input_keypad_client::release_keypad_data() +{ + if (_mem.is_valid()) + L4Re::Util::cap_alloc.free(_mem); + + if (_keypad_server.is_valid()) + L4Re::Util::cap_alloc.free(_keypad_server); + + if (_keymem_previous && (_keymem_previous != NULL)) + free(_keymem_previous); +} + +/* Scan the keypad, compare old and new states, and generate key events. */ + +void +Input_keypad_client::scan_keypad() +{ + uint32_t *keymem = (uint32_t *) _keymem; + uint32_t *keymem_previous = (uint32_t *) _keymem_previous; + int row, column, key_pressed; + uint32_t changed, mask; + Input_event event; + + for (column = 0; column < _keypad->columns(); column++) + { + /* Test for differences within each column. */ + + changed = keymem[column] ^ keymem_previous[column]; + + /* Transfer the current values to the previous values once used. */ + + keymem_previous[column] = keymem[column]; + + /* Move to the next column if no changes occurred. */ + + if (!changed) continue; + + /* Inspect each changed row position. */ + + mask = 1 << (_keypad->rows() - 1); + + for (row = 0; row < _keypad->rows(); row++) + { + if (changed & mask) + { + key_pressed = keymem[column] & mask; + + /* Construct an event using the appropriate key code. */ + + event = (Input_event) { + L4RE_EV_KEY, _keypad->code(column, row), key_pressed + }; + + /* Invoke the supplied handler. */ + + _handler(event, _priv); + } + mask >>= 1; + } + } +} + +/* Perform keypad scanning in a separate thread. */ + +void * +Input_keypad_client::scan_mainloop(void *data) +{ + /* Since this is a static method, obtain instance details from the data. */ + + Input_keypad_client *self = reinterpret_cast(data); + + while (1) + { + if (self->_handler) self->scan_keypad(); + l4_sleep(20); /* 20ms -> 50Hz */ + } + + return 0; +} + +/* Thread initialisation for the keypad scanning activity. */ + +void +Input_keypad_client::attach(Input_handler handler, void *priv) +{ + pthread_attr_t thread_attr; + struct sched_param sp; + + /* Record the handler and bundled private data. */ + + _handler = handler; + _priv = priv; + + /* Thread initialisation boilerplate. */ + + if (pthread_attr_init(&thread_attr)) + return; + + sp.sched_priority = 0x20; + pthread_attr_setschedparam(&thread_attr, &sp); + pthread_attr_setschedpolicy(&thread_attr, SCHED_L4); + pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED); + + /* Provide this instance as the private data. */ + + pthread_create(&_pthread, &thread_attr, scan_mainloop, this); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +PC_FILENAME := libdevice-keypad-ops + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/include/keypad-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/include/keypad-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,38 @@ +/* + * Keypad client to access keypad servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include +#include "keypad-ops.h" + +class Keypad_device_interface : public L4::Kobject_t +{ + L4_KOBJECT(Keypad_device_interface) + +public: + int get_keypad_data(L4::Cap mem) throw(); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/include/keypad-ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/include/keypad-ops.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,24 @@ +/* + * Keypad server operations. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum { Keypad_op_get_keypad_data }; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/include/keypad-server.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/include/keypad-server.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,47 @@ +/* + * Common keypad server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus + +/* Server object to provide keypad data access. */ + +class Keypad_server : public L4::Server_object_t +{ +private: + L4::Cap _mem; + +public: + /* Initialise the server with a capability referencing the exported memory. */ + + explicit Keypad_server(L4::Cap mem) + : _mem(mem) + {} + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,9 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := client letux400 qi_lb60 server + +include $(L4DIR)/mk/subdir.mk + +letux400: server +qi_lb60: server diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_keypad_client.o.a +PC_FILENAME := libdevice-keypad-client + +SRC_CC := keypad-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/keypad/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/client/keypad-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/client/keypad-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,37 @@ +/* + * Keypad client to access keypad servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "keypad-client.h" + +int +Keypad_device_interface::get_keypad_data(L4::Cap mem) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + /* Send a "receive item" for requesting a capability. */ + + s << L4::Ipc::Small_buf(mem); + + return l4_error(s.call(cap(), Keypad_op_get_keypad_data)); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/letux400/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/letux400/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_keypad_letux400 +PC_FILENAME := devices-keypad-letux400 + +SRC_CC := keypad-letux400.cc + +PRIVATE_INCDIR += $(PKGDIR)/keypad/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-gpio libdevice-util libdevice-keypad-server + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/letux400/keypad-letux400.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/letux400/keypad-letux400.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,213 @@ +/* + * Export the keypad GPIOs on the Letux 400 as a data space accessible via the + * "keypad" capability. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include "keypad-server.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +enum Jz4730_keypad_gpio +{ + Jz4730_keypad_gpio_inputs_count = 8, + Jz4730_keypad_gpio_outputs_count = 17, +}; + +/* Port A input pins. */ + +const uint8_t Jz4730_keypad_inputs[Jz4730_keypad_gpio_inputs_count] = { + 0, 1, 2, 3, 4, 5, 6, 7 +}; + +const Pin_slice Jz4730_keypad_inputs_mask = {0x000000ff, 0}; + +/* Port D output pins. */ + +const uint8_t Jz4730_keypad_outputs[Jz4730_keypad_gpio_outputs_count] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 +}; + +const Pin_slice Jz4730_keypad_outputs_mask = {0x2000ffff, 0}; + +/* Peripheral memory regions. */ + +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; + +/* GPIO abstractions. */ + +static void *gpio_port_a, *gpio_port_d; + +/* Keypad status: an array of keypad column values. */ + +uint32_t *keypad = 0; + +/* Imported keypad memory referenced by the array. */ + +void *keymem = 0; + +/* Thread details. */ + +static pthread_t _pthread; + + + +/* Initialise the pins for scanning the keypad. */ + +static void init_keyscan(void) +{ + jz4730_gpio_multi_setup(gpio_port_a, &Jz4730_keypad_inputs_mask, Hw::Gpio_chip::Input, 0); + jz4730_gpio_multi_config_pull(gpio_port_a, &Jz4730_keypad_inputs_mask, Hw::Gpio_chip::Pull_up); + jz4730_gpio_multi_setup(gpio_port_d, &Jz4730_keypad_outputs_mask, Hw::Gpio_chip::Input, 0); +} + +/* +Scan the keypad by enabling each output column and inspecting each input row. +Store each column bitmap in the keypad array. +*/ + +static void scan_keypad(void) +{ + uint8_t column, row, value; + + for (column = 0; column < Jz4730_keypad_gpio_outputs_count; column++) + { + jz4730_gpio_setup(gpio_port_d, Jz4730_keypad_outputs[column], Hw::Gpio_chip::Output, 0); + l4_sleep(1); + + value = 0; + + for (row = 0; row < Jz4730_keypad_gpio_inputs_count; row++) + value = (value << 1) | (jz4730_gpio_get(gpio_port_a, Jz4730_keypad_inputs[row]) ? 0 : 1); + + keypad[column] = value; + + jz4730_gpio_setup(gpio_port_d, Jz4730_keypad_outputs[column], Hw::Gpio_chip::Input, 0); + } + + l4_cache_clean_data((unsigned long) keypad, + (unsigned long) keypad + Jz4730_keypad_gpio_outputs_count); +} + +/* Set up access to memory. */ + +static int setup_memory(void) +{ + if (get_memory("jz4730-gpio", &gpio_virt_base, &gpio_virt_base_end) < 0) + return 1; + + gpio_port_a = jz4730_gpio_init(gpio_virt_base, gpio_virt_base + 0x30, 32); + gpio_port_d = jz4730_gpio_init(gpio_virt_base + 0x90, gpio_virt_base + 0xc0, 32); + + return 0; +} + + + +/* Worker thread for scanning the keypad. */ + +static void *scan_thread(void *data) +{ + (void) data; + + while (1) + { + scan_keypad(); + l4_sleep(20); /* 20ms -> 50Hz */ + } + + return 0; +} + +/* Thread initialisation. */ + +static int init_thread(void) +{ + pthread_attr_t thread_attr; + struct sched_param sp; + + if (pthread_attr_init(&thread_attr)) + return 1; + + sp.sched_priority = 0x20; + pthread_attr_setschedpolicy(&thread_attr, SCHED_L4); + pthread_attr_setschedparam(&thread_attr, &sp); + pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED); + + return pthread_create(&_pthread, &thread_attr, scan_thread, 0); +} + + + +static L4Re::Util::Registry_server<> server; + + + +/* Main program. */ + +int main(void) +{ + /* Memory allocation capability for the keypad data. */ + + L4::Cap mem; + l4_size_t mem_size = Jz4730_keypad_gpio_outputs_count * sizeof(uint32_t); + + if (setup_memory()) return 1; + + mem = allocate_data(mem_size, &keymem); + + if (!mem.is_valid()) return 1; + + keypad = (uint32_t *) keymem; + + /* Set up keypad access and start scanning. */ + + init_keyscan(); + + /* Set up a thread to scan the keypad concurrently with the server loop. */ + + init_thread(); + + /* Initialise and register a server object. */ + + Keypad_server server_obj(mem); + server.registry()->register_obj(&server_obj, "keypad"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/qi_lb60/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/qi_lb60/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_keypad_qi_lb60 +PC_FILENAME := devices-keypad-qi_lb60 + +SRC_CC := keypad-qi_lb60.cc + +PRIVATE_INCDIR += $(PKGDIR)/keypad/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-gpio libdevice-util libdevice-keypad-server + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/qi_lb60/keypad-qi_lb60.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/qi_lb60/keypad-qi_lb60.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,210 @@ +/* + * Export the keypad GPIOs on the Ben NanoNote as a data space accessible via + * the "keypad" capability. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include "keypad-server.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +enum Jz4740_keypad_gpio +{ + Jz4740_keypad_gpio_inputs_count = 8, + Jz4740_keypad_gpio_outputs_count = 8, +}; + +/* Port D input pins. */ + +const uint8_t Jz4740_keypad_inputs[Jz4740_keypad_gpio_inputs_count] = { + 18, 19, 20, 21, 22, 23, 24, 26 +}; + +const Pin_slice Jz4740_keypad_inputs_mask = {0x05fc0000, 0}; + +/* Port C output pins. */ + +const uint8_t Jz4740_keypad_outputs[Jz4740_keypad_gpio_outputs_count] = { + 10, 11, 12, 13, 14, 15, 16, 17 +}; + +const Pin_slice Jz4740_keypad_outputs_mask = {0x0003fc00, 0}; + +/* Peripheral memory regions. */ + +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; + +/* GPIO abstractions. */ + +static void *gpio_port_c, *gpio_port_d; + +/* Keypad status: an array of keypad column values. */ + +uint32_t *keypad = 0; + +/* Imported keypad memory referenced by the array. */ + +void *keymem = 0; + +/* Thread details. */ + +static pthread_t _pthread; + + + +/* Initialise the pins for scanning the keypad. */ + +static void init_keyscan(void) +{ + jz4740_gpio_multi_setup(gpio_port_d, &Jz4740_keypad_inputs_mask, Hw::Gpio_chip::Input, 0); + jz4740_gpio_multi_config_pull(gpio_port_d, &Jz4740_keypad_inputs_mask, Hw::Gpio_chip::Pull_up); + jz4740_gpio_multi_setup(gpio_port_c, &Jz4740_keypad_outputs_mask, Hw::Gpio_chip::Input, 0); +} + +/* +Scan the keypad by enabling each output column and inspecting each input row. +Store each column bitmap in the keypad array. +*/ + +static void scan_keypad(void) +{ + uint8_t column, row, value; + + for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++) + { + jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Hw::Gpio_chip::Output, 0); + l4_sleep(1); + + value = 0; + + for (row = 0; row < Jz4740_keypad_gpio_inputs_count; row++) + value = (value << 1) | (jz4740_gpio_get(gpio_port_d, Jz4740_keypad_inputs[row]) ? 0 : 1); + + keypad[column] = value; + + jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Hw::Gpio_chip::Input, 0); + } + + l4_cache_clean_data((unsigned long) keypad, + (unsigned long) keypad + Jz4740_keypad_gpio_outputs_count); +} + +/* Set up access to memory. */ + +static int setup_memory(void) +{ + if (get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end) < 0) + return 1; + + gpio_port_c = jz4740_gpio_init(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32); + gpio_port_d = jz4740_gpio_init(gpio_virt_base + 0x300, gpio_virt_base + 0x400, 32); + + return 0; +} + + + +/* Worker thread for scanning the keypad. */ + +static void *scan_thread(void *data) +{ + (void) data; + + while (1) + { + scan_keypad(); + l4_sleep(20); /* 20ms -> 50Hz */ + } + + return 0; +} + +/* Thread initialisation. */ + +static int init_thread(void) +{ + pthread_attr_t thread_attr; + struct sched_param sp; + + if (pthread_attr_init(&thread_attr)) + return 1; + + sp.sched_priority = 0x20; + pthread_attr_setschedpolicy(&thread_attr, SCHED_L4); + pthread_attr_setschedparam(&thread_attr, &sp); + pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED); + + return pthread_create(&_pthread, &thread_attr, scan_thread, 0); +} + + + +static L4Re::Util::Registry_server<> server; + + + +/* Main program. */ + +int main(void) +{ + /* Memory allocation capability for the keypad data. */ + + L4::Cap mem; + l4_size_t mem_size = Jz4740_keypad_gpio_outputs_count * sizeof(uint32_t); + + if (setup_memory()) return 1; + + mem = allocate_data(mem_size, &keymem); + + if (!mem.is_valid()) return 1; + + keypad = (uint32_t *) keymem; + + /* Set up keypad access and start scanning. */ + + init_keyscan(); + + /* Set up a thread to scan the keypad concurrently with the server loop. */ + + init_thread(); + + /* Initialise and register a server object. */ + + Keypad_server server_obj(mem); + server.registry()->register_obj(&server_obj, "keypad"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/server/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/server/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_keypad_server.o.a +PC_FILENAME := libdevice-keypad-server + +SRC_CC := keypad-server.cc + +PRIVATE_INCDIR += $(PKGDIR)/keypad/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/keypad/src/server/keypad-server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/keypad/src/server/keypad-server.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,52 @@ +/* + * Common keypad server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "keypad-client.h" +#include "keypad-server.h" + +#include +#include +#include +#include + +/* Handle invocations. */ + +int +Keypad_server::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) +{ + l4_msgtag_t tag; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case L4::Meta::Protocol: + return L4::Util::handle_meta_request(ios); + + case Keypad_op_get_keypad_data: + ios << _mem; + return L4_EOK; + + default: + return -L4_EBADPROTO; + } +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/include/lcd-device.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/include/lcd-device.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,112 @@ +/* + * LCD device support. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + +#include +#include + + + +#ifdef __cplusplus + +#include +#include + +class Lcd_device +{ +protected: + /* LCD peripheral abstraction. */ + + Lcd_chip *_chip; + + /* Display server abstraction. */ + + L4::Cap _display; + + /* Framebuffer virtual and physical addresses. */ + + l4_addr_t fb_vaddr, fb_paddr; + + /* Memory capability for the framebuffer. */ + + L4::Cap _fbmem; + + /* Display operations. */ + + virtual void disable_display(); + virtual void enable_display(); + +public: + /* Initialise a device with a controller and display object reference. */ + + Lcd_device(Lcd_chip *chip, L4::Cap display) + : _chip(chip), _display(display) + { + /* Subclasses must set up any memory. */ + } + + /* Framebuffer operations. */ + + virtual l4_addr_t get_framebuffer() + { + return fb_vaddr; + } + + virtual L4::Cap get_framebuffer_cap() + { + return _fbmem; + } + + /* Querying operations. */ + + virtual l4_size_t get_framebuffer_size() = 0; + virtual void get_view_info(l4re_video_view_info_t *view_info) = 0; + + /* Device operations. */ + + virtual void disable() = 0; + virtual void enable() = 0; + + /* Device access. */ + + static Lcd_device *get_device(); +}; + +#endif + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *lcd_get_device(void); +l4_addr_t lcd_get_framebuffer(void *lcd); +l4_size_t lcd_get_framebuffer_size(void *lcd); +void lcd_get_view_info(void *lcd, l4re_video_view_info_t *view_info); +void lcd_disable(void *lcd); +void lcd_enable(void *lcd); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/include/lcd-jz4740-device.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/include/lcd-jz4740-device.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,73 @@ +/* + * LCD device support for the JZ4740 and related SoCs. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include "lcd-device.h" + +#include +#include + +/* C++ language interface. */ + +#ifdef __cplusplus + +/* Support for specific JZ4740-based devices. */ + +class Lcd_jz4740_device : public Lcd_device +{ + /* DMA descriptor virtual and physical addresses. */ + + l4_addr_t desc_vaddr, desc_paddr; + +protected: + /* Device-specific memory allocation. */ + + int _setup_memory(); + +public: + /* Inherit constructor. */ + + Lcd_jz4740_device(Lcd_chip *chip, L4::Cap display) + : Lcd_device(chip, display) + { + _setup_memory(); + } + + /* Device operations. */ + + void disable(); + void enable(); + + l4_size_t get_framebuffer_size() + { + return static_cast(_chip)->get_screen_size(); + } + + void get_view_info(l4re_video_view_info_t *view_info); + + /* Common device instance. */ + + static Lcd_jz4740_device *device; +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/include/lcd-letux400.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/include/lcd-letux400.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,43 @@ +/* + * LCD device support for the Letux 400 notebook computer. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "lcd-jz4740-device.h" + +#ifdef __cplusplus + +class Lcd_letux400 : public Lcd_jz4740_device +{ +public: + /* Inherit constructor. */ + + Lcd_letux400(Lcd_chip *chip, L4::Cap display) + : Lcd_jz4740_device(chip, display) + { + } + + /* Common device instance. */ + + static Lcd_letux400 *device; +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/include/lcd-qi_lb60.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/include/lcd-qi_lb60.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,43 @@ +/* + * LCD device support for the Ben NanoNote. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "lcd-jz4740-device.h" + +#ifdef __cplusplus + +class Lcd_qi_lb60 : public Lcd_jz4740_device +{ +public: + /* Inherit constructor. */ + + Lcd_qi_lb60(Lcd_chip *chip, L4::Cap display) + : Lcd_jz4740_device(chip, display) + { + } + + /* Common device instance. */ + + static Lcd_qi_lb60 *device; +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := common jz4740 + +include $(L4DIR)/mk/subdir.mk + +jz4740: common diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/src/common/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/src/common/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = liblcd_device.o.a +PC_FILENAME := libdevice-lcd + +SRC_CC := lcd-device.cc + +PRIVATE_INCDIR += $(PKGDIR)/lcd/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-display-client libdrivers-lcd-headers + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/src/common/lcd-device.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/src/common/lcd-device.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,64 @@ +/* + * Common LCD device functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "lcd-device.h" + +void Lcd_device::disable_display() +{ + _display->disable(); +} + +void Lcd_device::enable_display() +{ + _display->enable(); +} + +// C language interface. + +void *lcd_get_device() +{ + return (void *) Lcd_device::get_device(); +} + +l4_addr_t lcd_get_framebuffer(void *lcd) +{ + return static_cast(lcd)->get_framebuffer(); +} + +l4_size_t lcd_get_framebuffer_size(void *lcd) +{ + return static_cast(lcd)->get_framebuffer_size(); +} + +void lcd_get_view_info(void *lcd, l4re_video_view_info_t *view_info) +{ + return static_cast(lcd)->get_view_info(view_info); +} + +void lcd_disable(void *lcd) +{ + static_cast(lcd)->disable(); +} + +void lcd_enable(void *lcd) +{ + static_cast(lcd)->enable(); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/src/jz4740/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/src/jz4740/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = liblcd_dev_jz4740.o.a +PC_FILENAME := libdevice-lcd-jz4740 + +SRC_CC := lcd-jz4740-device.cc + +PRIVATE_INCDIR += $(PKGDIR)/lcd/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-lcd libdrivers-lcd-jz4740 libdevice-cpm-client libdevice-panel-client libdevice-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lcd/src/jz4740/lcd-jz4740-device.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,280 @@ +/* + * Common LCD device support for the JZ4740 and related SoCs. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include "lcd-jz4740-device.h" + +#include +#include +#include +#include +#include +#include + +#include + +// Virtual addresses for the LCD register block. + +static l4_addr_t lcd_virt_base = 0, lcd_virt_base_end = 0; + +// LCD, CPM, display and panel device abstractions. + +static Lcd_jz4740_chip *lcd_chip = 0; + +static L4::Cap cpm_device; +static L4::Cap display_device; +static L4::Cap panel_device; + +// Panel definition. + +static struct Jz4740_lcd_panel panel; + + + +// CPM operations. + +static void set_timing() +{ + uint32_t pclk = lcd_chip->get_pixel_clock(); + + cpm_device->stop_lcd(); + + // Original comment: LCDClock > 2.5*Pixclock + // However, the documentation indicates that a TFT panel needs a device clock + // 1.5 times that of the pixel clock, and a STN panel needs a device clock 3 + // times that of the pixel clock. + + cpm_device->set_lcd_frequencies(pclk, 3); + cpm_device->update_output_frequency(); + cpm_device->start_lcd(); + + l4_sleep(1); // 1ms == 1000us +} + + + +// Disable the display. + +void +Lcd_jz4740_device::disable() +{ + Lcd_jz4740_chip *chip = static_cast(_chip); + + disable_display(); + chip->disable(); +} + +// Configure the peripheral and enable the display. + +void +Lcd_jz4740_device::enable() +{ + Lcd_jz4740_chip *chip = static_cast(_chip); + + chip->disable(); + chip->config((struct Jz4740_lcd_descriptor *) desc_vaddr, + (struct Jz4740_lcd_descriptor *) desc_paddr, + fb_paddr); + + // Initialise the clocks for the LCD controller. + + set_timing(); + enable_display(); + + chip->enable(); +} + +// Set up memory addresses for the peripheral, initialising the framebuffer and +// descriptor members. + +int +Lcd_jz4740_device::_setup_memory() +{ + // Framebuffer and descriptor sizes. + + unsigned long fb_size, desc_size; + + // Size of physically contiguous regions to be allocated. + + l4_size_t fb_size_out, desc_size_out; + + // Memory allocation capability. + + L4::Cap descmem; + + // Test for existing setup. + + if (fb_vaddr) + return 0; + + // Obtain capabilities for allocating memory. + + _fbmem = L4Re::Util::cap_alloc.alloc(); + if (!_fbmem.is_valid()) return 1; + + descmem = L4Re::Util::cap_alloc.alloc(); + if (!descmem.is_valid()) return 1; + + // Obtain the memory requirements. + + Lcd_jz4740_chip *chip = static_cast(_chip); + + fb_size = chip->get_screen_size(); + desc_size = chip->get_descriptors_size(); + + // Allocate memory for the framebuffer at 2**6 == 64 byte == 16 word alignment, + // also for the descriptors. + + const l4_size_t alloc_flags = L4Re::Mem_alloc::Continuous | L4Re::Mem_alloc::Pinned; + + if (L4Re::Env::env()->mem_alloc()->alloc(fb_size, _fbmem, alloc_flags, 6) || + L4Re::Env::env()->mem_alloc()->alloc(desc_size, descmem, alloc_flags, 6)) + return 1; + + // Map the allocated memory, obtaining virtual addresses. + + const l4_size_t attach_flags = L4Re::Rm::Search_addr | L4Re::Rm::Eager_map; + + fb_vaddr = 0; + desc_vaddr = 0; + + if (L4Re::Env::env()->rm()->attach(&fb_vaddr, fb_size, attach_flags, _fbmem, 0) || + L4Re::Env::env()->rm()->attach(&desc_vaddr, desc_size, attach_flags, descmem, 0)) + return 1; + + // Obtain physical addresses for the framebuffer and descriptors. + + fb_paddr = 0; + desc_paddr = 0; + + fb_size_out = fb_size; + desc_size_out = desc_size; + + if (_fbmem->phys(0, fb_paddr, fb_size_out) || + descmem->phys(0, desc_paddr, desc_size_out)) + return 1; + + // Test the mapped region sizes. + + if ((fb_size_out != fb_size) || (desc_size_out != desc_size)) + return 1; + + return 0; +} + +// Populate a view information structure. + +void +Lcd_jz4740_device::get_view_info(l4re_video_view_info_t *view_info) +{ + // Populate the L4Re framebuffer description with details from the + // somewhat similar panel description. + + Lcd_jz4740_chip *chip = static_cast(_chip); + struct Jz4740_lcd_panel *panel = chip->get_panel(); + + view_info->width = panel->width; + view_info->height = panel->height; + view_info->pixel_info.bytes_per_pixel = (panel->bpp + 7) / 8; + view_info->bytes_per_line = chip->get_line_size(); + + switch (panel->bpp) + { + case 32: + view_info->pixel_info.r.shift = 16; view_info->pixel_info.r.size = 8; + view_info->pixel_info.g.shift = 8; view_info->pixel_info.g.size = 8; + view_info->pixel_info.b.shift = 0; view_info->pixel_info.b.size = 8; + break; + + case 8: + view_info->pixel_info.r.shift = 5; view_info->pixel_info.r.size = 3; + view_info->pixel_info.g.shift = 2; view_info->pixel_info.g.size = 3; + view_info->pixel_info.b.shift = 0; view_info->pixel_info.b.size = 2; + break; + + case 4: + view_info->pixel_info.r.shift = 3; view_info->pixel_info.r.size = 1; + view_info->pixel_info.g.shift = 1; view_info->pixel_info.g.size = 2; + view_info->pixel_info.b.shift = 0; view_info->pixel_info.b.size = 1; + break; + + case 16: + default: + view_info->pixel_info.r.shift = 11; view_info->pixel_info.r.size = 5; + view_info->pixel_info.g.shift = 5; view_info->pixel_info.g.size = 6; + view_info->pixel_info.b.shift = 0; view_info->pixel_info.b.size = 5; + break; + } + + view_info->pixel_info.a.shift = 0; + view_info->pixel_info.a.size = 0; +} + +// Access to peripheral memory. + +static int setup_memory() +{ + if (get_memory("jz4740-lcd", &lcd_virt_base, &lcd_virt_base_end)) + return 1; + + // Obtain access to the CPM, display and panel devices. + + cpm_device = L4Re::Env::env()->get_cap("cpm"); + if (!cpm_device.is_valid()) return 1; + + display_device = L4Re::Env::env()->get_cap("display"); + if (!display_device.is_valid()) return 1; + + panel_device = L4Re::Env::env()->get_cap("panel"); + if (!panel_device.is_valid()) return 1; + + // Populate the panel. + + if (panel_device->get_panel((uint8_t *) &panel, sizeof(panel))) + return 1; + + // Initialise the LCD abstraction. + + lcd_chip = new Lcd_jz4740_chip(lcd_virt_base, &panel); + + return 0; +} + +// Device initialisation. + +Lcd_jz4740_device *Lcd_jz4740_device::device = 0; + +Lcd_device *Lcd_device::get_device() +{ + if (Lcd_jz4740_device::device) return Lcd_jz4740_device::device; + + if (setup_memory()) return 0; + + // Initialise the common device. + + Lcd_jz4740_device::device = new Lcd_jz4740_device(lcd_chip, display_device); + + return Lcd_jz4740_device::device; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := common cpm gpio i2c keypad lcd pwm + +include $(L4DIR)/mk/subdir.mk + +cpm: common +gpio: common +i2c: common +keypad: common +lcd: common +pwm: common diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/common/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/common/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/common/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/common/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR = ../../.. +L4DIR ?= $(PKGDIR)/../.. + +PC_FILENAME := libdrivers-common + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/common/include/hw_mmio_register_block.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/common/include/hw_mmio_register_block.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,47 @@ +/* + * (c) 2014 Alexander Warg + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ +#pragma once + +#include "hw_register_block.h" + +namespace Hw { + +class Mmio_register_block_base +{ +private: + l4_addr_t _base; + l4_addr_t _shift; + +public: + explicit Mmio_register_block_base(l4_addr_t base = 0, l4_addr_t shift = 0) + : _base(base), _shift(shift) {} + + template< typename T > + T read(l4_addr_t reg) const + { return *reinterpret_cast(_base + (reg << _shift)); } + + template< typename T > + void write(T value, l4_addr_t reg) const + { *reinterpret_cast(_base + (reg << _shift)) = value; } + + void set_base(l4_addr_t base) { _base = base; } + void set_shift(l4_addr_t shift) { _shift = shift; } +}; + +template< unsigned MAX_BITS = 32 > +struct Mmio_register_block : + Register_block_impl, MAX_BITS>, + Mmio_register_block_base +{ + explicit Mmio_register_block(l4_addr_t base = 0, l4_addr_t shift = 0) + : Mmio_register_block_base(base, shift) {} +}; + +} + + diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/common/include/hw_register_block.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/common/include/hw_register_block.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,499 @@ +/* + * (c) 2014 Alexander Warg + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ +#pragma once + +#include +#include + +namespace Hw { + + +/* EXAMPLE usage: + +\code + +void test() +{ + // create a register block reference for max. 16bit accesses, using a + // MMIO register block implementation (at address 0x1000). + Hw::Register_block<16> regs = new Hw::Mmio_register_block<16>(0x1000); + + // Alternatively it is allowed to use an implementation that allows + // wider access than actually needed. + Hw::Register_block<16> regs = new Hw::Mmio_register_block<32>(0x1000); + + // read a 16bit register at offset 8byte + unsigned short x = regs.r<16>(8); + unsigned short x1 = regs[8]; // alternative + + // read an 8bit register at offset 0byte + unsigned v = regs.r<8>(0); + + // do a 16bit write to register at offset 2byte (four variants) + regs[2] = 22; + regs.r<16>(2) = 22; + regs[2].write(22); + regs.r<16>().write(22); + + // do an 8bit write (two variants) + regs.r<8>(0) = 9; + regs.r<8>(0).write(9); + + // do 16bit read-modify-write (two variants) + regs[4].modify(0xf, 3); // clear 4 lowest bits and set them to 3 + regs.r<16>(4).modify(0xf, 3); + + // do 8bit read-modify-write + regs.r<8>(0).modify(0xf, 3); + + // fails to compile, because of too wide access + // (32 bit access but regs is Hw::Register_block<16>) + unsigned long v = regs.r<32>(4) +} + +\endcode +*/ + + +/** + * \brief Abstract register block interface + * \tparam MAX_BITS The maximum access width for the registers. + * + * This interfaces is based on virtual do_read_ and do_write_ + * methods that have to be implemented up to the maximum access width. + */ +template< unsigned MAX_BITS = 32 > +struct Register_block_base; + +template<> +struct Register_block_base<8> +{ + virtual l4_uint8_t do_read_8(l4_addr_t reg) const = 0; + virtual void do_write_8(l4_uint8_t value, l4_addr_t reg) = 0; + virtual ~Register_block_base() = 0; +}; + +inline Register_block_base<8>::~Register_block_base() {} + +template<> +struct Register_block_base<16> : Register_block_base<8> +{ + virtual l4_uint16_t do_read_16(l4_addr_t reg) const = 0; + virtual void do_write_16(l4_uint16_t value, l4_addr_t reg) = 0; +}; + +template<> +struct Register_block_base<32> : Register_block_base<16> +{ + virtual l4_uint32_t do_read_32(l4_addr_t reg) const = 0; + virtual void do_write_32(l4_uint32_t value, l4_addr_t reg) = 0; +}; + +template<> +struct Register_block_base<64> : Register_block_base<32> +{ + virtual l4_uint64_t do_read_64(l4_addr_t reg) const = 0; + virtual void do_write_64(l4_uint64_t value, l4_addr_t reg) = 0; +}; +#undef REGBLK_READ_TEMPLATE +#undef REGBLK_WRITE_TEMPLATE + +template +struct Register_block_modify_mixin +{ + template< typename T > + T modify(T clear_bits, T set_bits, l4_addr_t reg) const + { + CHILD const *c = static_cast(this); + T r = (c->template read(reg) & ~clear_bits) | set_bits; + c->template write(r, reg); + return r; + } + + template< typename T > + T set(T set_bits, l4_addr_t reg) const + { return this->template modify(T(0), set_bits, reg); } + + template< typename T > + T clear(T clear_bits, l4_addr_t reg) const + { return this->template modify(clear_bits, T(0), reg); } +}; + + +#define REGBLK_READ_TEMPLATE(sz) \ + template< typename T > \ + typename cxx::enable_if::type read(l4_addr_t reg) const \ + { \ + union X { T t; l4_uint##sz##_t v; } m; \ + m.v = _b->do_read_##sz (reg); \ + return m.t; \ + } + +#define REGBLK_WRITE_TEMPLATE(sz) \ + template< typename T > \ + void write(T value, l4_addr_t reg, typename cxx::enable_if::type = T()) const \ + { \ + union X { T t; l4_uint##sz##_t v; } m; \ + m.t = value; \ + _b->do_write_##sz(m.v, reg); \ + } + +/** + * \brief Helper template that translates to the Register_block_base + * interface. + * \tparam BLOCK The type of the Register_block_base interface to use. + * + * This helper translates read(), write(), set(), clear(), + * and modify() calls to BLOCK::do_read_ and BLOCK::do_write_. + */ +template< typename BLOCK > +class Register_block_tmpl +: public Register_block_modify_mixin > +{ +private: + BLOCK *_b; + +public: + Register_block_tmpl(BLOCK *blk) : _b(blk) {} + Register_block_tmpl() = default; + + operator BLOCK * () const { return _b; } + + REGBLK_READ_TEMPLATE(8) + REGBLK_WRITE_TEMPLATE(8) + REGBLK_READ_TEMPLATE(16) + REGBLK_WRITE_TEMPLATE(16) + REGBLK_READ_TEMPLATE(32) + REGBLK_WRITE_TEMPLATE(32) + REGBLK_READ_TEMPLATE(64) + REGBLK_WRITE_TEMPLATE(64) +}; + + +#undef REGBLK_READ_TEMPLATE +#undef REGBLK_WRITE_TEMPLATE + +namespace __Type_helper { + template struct Unsigned; + template<> struct Unsigned<8> { typedef l4_uint8_t type; }; + template<> struct Unsigned<16> { typedef l4_uint16_t type; }; + template<> struct Unsigned<32> { typedef l4_uint32_t type; }; + template<> struct Unsigned<64> { typedef l4_uint64_t type; }; +}; + + +/** + * \brief Single read only register inside a Register_block_base interface. + * \tparam BITS The access with of the register in bits. + * \tparam BLOCK The type for the Register_block_base interface. + * \note Objects of this type must be used only in temporary contexts + * not in global, class, or object scope. + * + * Allows simple read only access to a hardware register. + */ +template< unsigned BITS, typename BLOCK > +class Ro_register_tmpl +{ +protected: + BLOCK _b; + unsigned _o; + +public: + typedef typename __Type_helper::Unsigned::type value_type; + + Ro_register_tmpl(BLOCK const &blk, unsigned offset) : _b(blk), _o(offset) {} + Ro_register_tmpl() = default; + + /** + * \brief read the value from the hardware register. + * \return value read from the hardware register. + */ + operator value_type () const + { return _b.template read(_o); } + + /** + * \brief read the value from the hardware register. + * \return value from the hardware register. + */ + value_type read() const + { return _b.template read(_o); } +}; + + +/** + * \brief Single hardware register inside a Register_block_base interface. + * \tparam BITS The access width for the register in bits. + * \tparam BLOCK the type of the Register_block_base interface. + * \note Objects of this type msut be used only in temporary contexts + * not in global, class, or object scope. + */ +template< unsigned BITS, typename BLOCK > +class Register_tmpl : public Ro_register_tmpl +{ +public: + typedef typename Ro_register_tmpl::value_type value_type; + + Register_tmpl(BLOCK const &blk, unsigned offset) + : Ro_register_tmpl(blk, offset) + {} + + Register_tmpl() = default; + + /** + * \brief write \a val into the hardware register. + * \param val the value to write into the hardware register. + */ + Register_tmpl &operator = (value_type val) + { this->_b.template write(val, this->_o); return *this; } + + /** + * \brief write \a val into the hardware register. + * \param val the value to write into the hardware register. + */ + void write(value_type val) + { this->_b.template write(val, this->_o); } + + /** + * \brief set bits in \a set_bits in the hardware register. + * \param set_bits bits to be set within the hardware register. + * + * This is a read-modify-write function that does a logical or + * of the old value from the register with \a set_bits. + * + * \code + * unsigned old_value = read(); + * write(old_value | set_bits); + * \endcode + */ + value_type set(value_type set_bits) + { return this->_b.template set(set_bits, this->_o); } + + /** + * \brief clears bits in \a clear_bits in the hardware register. + * \param clear_bits bits to be cleared within the hardware register. + * + * This is a read-modify-write function that does a logical and + * of the old value from the register with the negated value of + * \a clear_bits. + * + * \code + * unsigned old_value = read(); + * write(old_value & ~clear_bits); + * \endcode + */ + value_type clear(value_type clear_bits) + { return this->_b.template clear(clear_bits, this->_o); } + + /** + * \brief clears bits in \a clear_bits and sets bits in \a set_bits + * in the hardware register. + * \param clear_bits bits to be cleared within the hardware register. + * \param set_bits bits to set in the hardware register. + * + * This is a read-modify-write function that first does a logical and + * of the old value from the register with the negated value of + * \a clear_bits and then does a logical or with \a set_bits. + * + * \code{.c} + * unsigned old_value = read(); + * write((old_value & ~clear_bits) | set_bits); + * \endcode + */ + value_type modify(value_type clear_bits, value_type set_bits) + { return this->_b.template modify(clear_bits, set_bits, this->_o); } +}; + + +/** + * \brief Handles a reference to a register block of the given + * maximum access width. + * \tparam MAX_BITS Maximum access width for the registers in this + * block. + * \tparam BLOCK Type implementing the register accesses (read<>(), write<>(), + * modify<>(), set<>(), and clear<>()). + * + * Provides access to registers in this block via r() and + * operator[](). + */ +template< + unsigned MAX_BITS, + typename BLOCK = Register_block_tmpl< + Register_block_base + > +> +class Register_block +{ +private: + template< unsigned B, typename BLK > friend class Register_block; + template< unsigned B, typename BLK > friend class Ro_register_block; + typedef BLOCK Block; + Block _b; + +public: + Register_block() = default; + Register_block(Block const &blk) : _b(blk) {} + Register_block &operator = (Block const &blk) + { _b = blk; return *this; } + + template< unsigned BITS > + Register_block(Register_block blk) : _b(blk._b) {} + + typedef Register_tmpl Register; + typedef Ro_register_tmpl Ro_register; + + /** + * \brief Read only access to register at offset \a offset. + * \tparam BITS the access width in bits for the register. + * \param offset The offset of the register within the register file. + * \return register object allowing read only access with width \a BITS. + */ + template< unsigned BITS > + Ro_register_tmpl r(unsigned offset) const + { return Ro_register_tmpl(this->_b, offset); } + + /** + * \brief Read only access to register at offset \a offset. + * \param offset The offset of the register within the register file. + * \return register object allowing read only access with width \a MAX_BITS. + */ + Ro_register operator [] (unsigned offset) const + { return this->r(offset); } + + + /** + * \brief Read/write access to register at offset \a offset. + * \tparam BITS the access width in bits for the register. + * \param offset The offset of the register within the register file. + * \return register object allowing read and write access with width \a BITS. + */ + template< unsigned BITS > + Register_tmpl r(unsigned offset) + { return Register_tmpl(this->_b, offset); } + + /** + * \brief Read/write access to register at offset \a offset. + * \param offset The offset of the register within the register file. + * \return register object allowing read and write access with + * width \a MAX_BITS. + */ + Register operator [] (unsigned offset) + { return this->r(offset); } +}; + +/** + * \brief Handles a reference to a read only register block of the given + * maximum access width. + * \tparam MAX_BITS Maximum access width for the registers in this block. + * \tparam BLOCK Type implementing the register accesses (read<>()), + * + * Provides read only access to registers in this block via r() + * and operator[](). + */ +template< + unsigned MAX_BITS, + typename BLOCK = Register_block_tmpl< + Register_block_base const + > +> +class Ro_register_block +{ +private: + template< unsigned B, typename BLK > friend class Ro_register_block; + typedef BLOCK Block; + Block _b; + +public: + Ro_register_block() = default; + Ro_register_block(BLOCK const &blk) : _b(blk) {} + + template< unsigned BITS > + Ro_register_block(Register_block const &blk) : _b(blk._b) {} + + typedef Ro_register_tmpl Ro_register; + typedef Ro_register Register; + + /** + * \brief Read only access to register at offset \a offset. + * \param offset The offset of the register within the register file. + * \return register object allowing read only access with width \a MAX_BITS. + */ + Ro_register operator [] (unsigned offset) const + { return Ro_register(this->_b, offset); } + + /** + * \brief Read only access to register at offset \a offset. + * \tparam BITS the access width in bits for the register. + * \param offset The offset of the register within the register file. + * \return register object allowing read only access with width \a BITS. + */ + template< unsigned BITS > + Ro_register_tmpl r(unsigned offset) const + { return Ro_register_tmpl(this->_b, offset); } +}; + + +/** + * \brief Implementation helper for register blocks. + * \param BASE The class implementing read<> and write<> template functions + * for accessing the registers. This class must inherit from + * Register_block_impl. + * \param MAX_BITS The maximum access width for the register file. + * Supported values are 8, 16, 32, or 64. + * + * + * This template allows easy implementation of register files by providing + * read<> and write<> template functions, see Mmio_register_block + * as an example. + */ +template< typename BASE, unsigned MAX_BITS = 32 > +struct Register_block_impl; + +#define REGBLK_IMPL_RW_TEMPLATE(sz, ...) \ + l4_uint##sz##_t do_read_##sz(l4_addr_t reg) const \ + { return static_cast(this)->template read(reg); } \ + \ + void do_write_##sz(l4_uint##sz##_t value, l4_addr_t reg) \ + { return static_cast(this)->template write(value, reg); } + + +template< typename BASE > +struct Register_block_impl : public Register_block_base<8> +{ + REGBLK_IMPL_RW_TEMPLATE(8); +}; + +template< typename BASE > +struct Register_block_impl : public Register_block_base<16> +{ + REGBLK_IMPL_RW_TEMPLATE(8); + REGBLK_IMPL_RW_TEMPLATE(16); +}; + +template< typename BASE > +struct Register_block_impl : public Register_block_base<32> +{ + REGBLK_IMPL_RW_TEMPLATE(8); + REGBLK_IMPL_RW_TEMPLATE(16); + REGBLK_IMPL_RW_TEMPLATE(32); +}; + +template< typename BASE > +struct Register_block_impl : public Register_block_base<64> +{ + REGBLK_IMPL_RW_TEMPLATE(8); + REGBLK_IMPL_RW_TEMPLATE(16); + REGBLK_IMPL_RW_TEMPLATE(32); + REGBLK_IMPL_RW_TEMPLATE(64); +}; + +#undef REGBLK_IMPL_RW_TEMPLATE + +/** \brief Dummy register block to be used as a placeholder */ +extern Register_block<64> dummy_register_block; + +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/include/cpm-jz4730.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/include/cpm-jz4730.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,115 @@ +/* + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "cpm.h" + +#include +#include + + + +#ifdef __cplusplus + +#include + +/* A simple abstraction for accessing the CPM registers. + * A proper device could inherit from Hw::Device and use an + * Int_property for _exclk_freq. */ + +class Cpm_jz4730_chip : public Cpm_chip +{ +private: + Hw::Register_block<32> _regs; + uint32_t _exclk_freq; + + int pll_enabled(); + int pll_bypassed(); + +public: + Cpm_jz4730_chip(l4_addr_t addr, uint32_t exclk_freq); + + int have_clock(); + void start_clock(); + + int have_pll(); + + uint16_t get_multiplier(); + uint8_t get_input_division(); + uint8_t get_output_division(); + + uint8_t _get_divider(uint32_t reg, uint32_t mask, uint8_t shift); + uint8_t get_cpu_divider(); + uint8_t get_hclock_divider(); + uint8_t get_pclock_divider(); + uint8_t get_memory_divider(); + uint8_t get_source_divider(); + + uint16_t get_lcd_pixel_divider(); + uint32_t get_lcd_pixel_frequency(); + + void set_lcd_device_divider(uint8_t division); + void set_lcd_pixel_divider(uint16_t division); + void set_lcd_frequencies(uint32_t pclk, uint8_t ratio); + + void start_lcd(); + void stop_lcd(); + + uint32_t get_pll_frequency(); + uint32_t get_output_frequency(); + void update_output_frequency(); + + uint32_t get_cpu_frequency(); + uint32_t get_hclock_frequency(); + uint32_t get_pclock_frequency(); + uint32_t get_memory_frequency(); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4730_cpm_init(l4_addr_t cpm_base); + +int jz4730_cpm_have_pll(void *cpm); + +int jz4730_cpm_have_clock(void *cpm); +void jz4730_cpm_start_clock(void *cpm); + +void jz4730_cpm_start_lcd(void *cpm); +void jz4730_cpm_stop_lcd(void *cpm); + +uint16_t jz4730_cpm_get_lcd_pixel_divider(void *cpm); +uint32_t jz4730_cpm_get_lcd_pixel_frequency(void *cpm); + +void jz4730_cpm_set_lcd_frequencies(void *cpm, uint32_t pclk, uint8_t ratio); +void jz4730_cpm_update_output_frequency(void *cpm); + +uint32_t jz4730_cpm_get_cpu_frequency(void *cpm); +uint32_t jz4730_cpm_get_hclock_frequency(void *cpm); +uint32_t jz4730_cpm_get_output_frequency(void *cpm); +uint32_t jz4730_cpm_get_pclock_frequency(void *cpm); +uint32_t jz4730_cpm_get_memory_frequency(void *cpm); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/include/cpm-jz4740.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/include/cpm-jz4740.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,115 @@ +/* + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "cpm.h" + +#include +#include + + + +#ifdef __cplusplus + +#include + +/* A simple abstraction for accessing the CPM registers. + * A proper device could inherit from Hw::Device and use an + * Int_property for _exclk_freq. */ + +class Cpm_jz4740_chip : public Cpm_chip +{ +private: + Hw::Register_block<32> _regs; + uint32_t _exclk_freq; + + int pll_enabled(); + int pll_bypassed(); + +public: + Cpm_jz4740_chip(l4_addr_t addr, uint32_t exclk_freq); + + int have_clock(); + void start_clock(); + + int have_pll(); + + uint16_t get_multiplier(); + uint8_t get_input_division(); + uint8_t get_output_division(); + + uint8_t _get_divider(uint32_t reg, uint32_t mask, uint8_t shift); + uint8_t get_cpu_divider(); + uint8_t get_hclock_divider(); + uint8_t get_pclock_divider(); + uint8_t get_memory_divider(); + uint8_t get_source_divider(); + + uint16_t get_lcd_pixel_divider(); + uint32_t get_lcd_pixel_frequency(); + + void set_lcd_device_divider(uint8_t division); + void set_lcd_pixel_divider(uint16_t division); + void set_lcd_frequencies(uint32_t pclk, uint8_t ratio); + + void start_lcd(); + void stop_lcd(); + + uint32_t get_pll_frequency(); + uint32_t get_output_frequency(); + void update_output_frequency(); + + uint32_t get_cpu_frequency(); + uint32_t get_hclock_frequency(); + uint32_t get_pclock_frequency(); + uint32_t get_memory_frequency(); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4740_cpm_init(l4_addr_t cpm_base); + +int jz4740_cpm_have_pll(void *cpm); + +int jz4740_cpm_have_clock(void *cpm); +void jz4740_cpm_start_clock(void *cpm); + +void jz4740_cpm_start_lcd(void *cpm); +void jz4740_cpm_stop_lcd(void *cpm); + +uint16_t jz4740_cpm_get_lcd_pixel_divider(void *cpm); +uint32_t jz4740_cpm_get_lcd_pixel_frequency(void *cpm); + +void jz4740_cpm_set_lcd_frequencies(void *cpm, uint32_t pclk, uint8_t ratio); +void jz4740_cpm_update_output_frequency(void *cpm); + +uint32_t jz4740_cpm_get_cpu_frequency(void *cpm); +uint32_t jz4740_cpm_get_hclock_frequency(void *cpm); +uint32_t jz4740_cpm_get_output_frequency(void *cpm); +uint32_t jz4740_cpm_get_pclock_frequency(void *cpm); +uint32_t jz4740_cpm_get_memory_frequency(void *cpm); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/include/cpm-jz4780.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/include/cpm-jz4780.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,202 @@ +/* + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "cpm.h" + +#include +#include + + + +#ifdef __cplusplus + +#include + +/* A simple abstraction for accessing the CPM registers. + * A proper device could inherit from Hw::Device and use an + * Int_property for _exclk_freq and _rtclk_freq. */ + +class Cpm_jz4780_chip : public Cpm_chip +{ +private: + Hw::Register_block<32> _regs; + uint32_t _exclk_freq, _rtclk_freq; + + // Utility methods. + + uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); + void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); + uint8_t _get_divider(uint32_t reg, uint32_t mask, uint8_t shift); + + // PLL control. + + int have_pll(uint32_t pll_reg); + int pll_enabled(uint32_t pll_reg); + int pll_bypassed(uint32_t pll_reg); + + // General frequency modifiers. + + uint16_t get_multiplier(uint32_t pll_reg); + void set_multiplier(uint32_t pll_reg, uint16_t multiplier); + uint8_t get_input_division(uint32_t pll_reg); + void set_input_division(uint32_t pll_reg, uint8_t divider); + uint8_t get_output_division(uint32_t pll_reg); + void set_output_division(uint32_t pll_reg, uint8_t divider); + + // Clock dividers. + + void set_lcd_pixel_divider(uint16_t division); + + // Clock control. + + void _update_i2c(uint8_t channel, int enable); + + // Input frequencies. + + uint32_t get_pll_frequency(uint32_t pll_reg); + + // Clock sources. + + void set_hclock2_source(uint8_t source); + void set_lcd_source(uint8_t source); + +public: + void set_pclock_source(uint8_t source); + Cpm_jz4780_chip(l4_addr_t addr, uint32_t exclk_freq, uint32_t rtclk_freq); + + int have_clock(); + void start_clock(); + + // Clock divider values. + + uint8_t get_cpu_divider(); + uint8_t get_hclock0_divider(); + uint8_t get_hclock2_divider(); + uint8_t get_pclock_divider(); + uint8_t get_lcd_pixel_divider(); + uint8_t get_memory_divider(); + + // Clock control. + + void start_lcd(); + void stop_lcd(); + + void start_i2c(uint8_t channel); + void stop_i2c(uint8_t channel); + + // Input frequencies. + + uint8_t get_main_source(); + uint32_t get_main_frequency(); + + // Clock sources, providing the input frequency. + + uint8_t get_cpu_source(); + uint8_t get_hclock0_source(); + uint8_t get_hclock2_source(); + uint8_t get_lcd_source(); + uint8_t get_memory_source(); + uint8_t get_pclock_source(); + + uint32_t get_cpu_source_frequency(); + uint32_t get_hclock0_source_frequency(); + uint32_t get_hclock2_source_frequency(); + uint32_t get_lcd_source_frequency(); + uint32_t get_memory_source_frequency(); + uint32_t get_pclock_source_frequency(); + + // Final, calculated frequencies. + + uint32_t get_cpu_frequency(); + uint32_t get_hclock0_frequency(); + uint32_t get_hclock2_frequency(); + uint32_t get_lcd_pixel_frequency(); + uint32_t get_memory_frequency(); + uint32_t get_pclock_frequency(); + + uint32_t get_apll_frequency(); + uint32_t get_epll_frequency(); + uint32_t get_mpll_frequency(); + uint32_t get_vpll_frequency(); + + void set_lcd_pixel_frequency(uint32_t pclk); + void set_lcd_frequencies(uint32_t pclk, uint8_t multiplier); + void set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); + + void update_output_frequency(); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4780_cpm_init(l4_addr_t cpm_base); + +int jz4780_cpm_have_clock(void *cpm); +void jz4780_cpm_start_clock(void *cpm); + +void jz4780_cpm_start_lcd(void *cpm); +void jz4780_cpm_stop_lcd(void *cpm); + +uint8_t jz4780_cpm_get_cpu_divider(void *cpm); +uint8_t jz4780_cpm_get_hclock0_divider(void *cpm); +uint8_t jz4780_cpm_get_hclock2_divider(void *cpm); +uint8_t jz4780_cpm_get_lcd_pixel_divider(void *cpm); +uint8_t jz4780_cpm_get_memory_divider(void *cpm); +uint8_t jz4780_cpm_get_pclock_divider(void *cpm); + +uint8_t jz4780_cpm_get_hclock0_source(void *cpm); +uint8_t jz4780_cpm_get_hclock2_source(void *cpm); +uint8_t jz4780_cpm_get_lcd_source(void *cpm); +uint8_t jz4780_cpm_get_memory_source(void *cpm); +uint8_t jz4780_cpm_get_pclock_source(void *cpm); + +uint32_t jz4780_cpm_get_hclock0_source_frequency(void *cpm); +uint32_t jz4780_cpm_get_hclock2_source_frequency(void *cpm); +uint32_t jz4780_cpm_get_lcd_source_frequency(void *cpm); +uint32_t jz4780_cpm_get_memory_source_frequency(void *cpm); +uint32_t jz4780_cpm_get_pclock_source_frequency(void *cpm); + +void jz4780_cpm_set_pclock_source(void *cpm, uint8_t source); + +uint8_t jz4780_cpm_get_main_source(void *cpm); +uint32_t jz4780_cpm_get_main_frequency(void *cpm); + +uint32_t jz4780_cpm_get_cpu_frequency(void *cpm); +uint32_t jz4780_cpm_get_hclock0_frequency(void *cpm); +uint32_t jz4780_cpm_get_hclock2_frequency(void *cpm); +uint32_t jz4780_cpm_get_lcd_pixel_frequency(void *cpm); +uint32_t jz4780_cpm_get_memory_frequency(void *cpm); +uint32_t jz4780_cpm_get_pclock_frequency(void *cpm); + +uint32_t jz4780_cpm_get_apll_frequency(void *cpm); +uint32_t jz4780_cpm_get_epll_frequency(void *cpm); +uint32_t jz4780_cpm_get_mpll_frequency(void *cpm); +uint32_t jz4780_cpm_get_vpll_frequency(void *cpm); + +void jz4780_cpm_set_lcd_pixel_frequency(void *cpm, uint32_t pclk); +void jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/include/cpm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/include/cpm.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,44 @@ +/* + * Clock and power management (CPM) abstractions. + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +#ifdef __cplusplus + +/* A simple abstraction for accessing the CPM registers. */ + +class Cpm_chip +{ +public: + virtual void set_lcd_frequencies(uint32_t pclk, uint8_t ratio) = 0; + + virtual void start_lcd() = 0; + virtual void stop_lcd() = 0; + + virtual void update_output_frequency() = 0; +}; + +#endif /* __cplusplus */ diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libcpm.o.a +PC_FILENAME := libdrivers-cpm + +SRC_CC := jz4730.cc jz4740.cc jz4780.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/cpm/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/src/jz4730.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/src/jz4730.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,446 @@ +/* + * Clock and power management. This exposes the combined functionality + * provided by the jz4730. The power management functionality could be exposed + * using a separate driver. + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include "cpm-jz4730.h" + + + +enum Regs : unsigned +{ + Clock_control = 0x000, // CFCR (CPCCR in JZ4740) + Pll_control = 0x010, // PLCR1 (CPPCR in JZ4740) + Clock_gate = 0x020, // MSCR (CLKGR in JZ4740) + Sleep_control = 0x024, // SCR + Lcd_divider = 0x060, // CFCR2 +}; + +enum Clock_bits : unsigned +{ + Clock_enable = 20, // UPE + Clock_memory_divider = 16, // MFR + Clock_lcd_divider = 12, // LFR + Clock_pclock_divider = 8, // PFR (slow APB peripherals) + Clock_hclock_divider = 4, // SFR (fast AHB peripherals) + Clock_cpu_divider = 0, // IFR +}; + +enum Pll_bits : unsigned +{ + Pll_multiplier = 23, // PLL1FD + Pll_input_division = 18, // PLL1RD + Pll_output_division = 16, // PLL1OD + Pll_stable = 10, // PLL1S + Pll_bypassed = 9, // PLL1BP + Pll_enabled = 8, // PLL1EN +}; + +enum Clock_gate_bits : unsigned +{ + Clock_gate_lcd = 7, // LCD + Clock_gate_timer = 3, // OST +}; + +enum Lcd_divider_bits : unsigned +{ + Lcd_divider_value = 0, // PIXFR (in CFCR2) +}; + + + +// If implemented as a Hw::Device, various properties would be +// initialised in the constructor and obtained from the device tree +// definitions. + +Cpm_jz4730_chip::Cpm_jz4730_chip(l4_addr_t addr, uint32_t exclk_freq) +: _exclk_freq(exclk_freq) +{ + _regs = new Hw::Mmio_register_block<32>(addr); + + // add_cid("cpm"); + // add_cid("cpm-jz4730"); + // register_property("exclk_freq", &_exclk_freq); +} + +// Clock/timer control. + +int +Cpm_jz4730_chip::have_clock() +{ + return !(_regs[Clock_gate] & (1 << Clock_gate_timer)); +} + +void +Cpm_jz4730_chip::start_clock() +{ + _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_timer); +} + +// PLL control. + +// Return whether the PLL is stable. + +int +Cpm_jz4730_chip::have_pll() +{ + return _regs[Pll_control] & (1 << Pll_stable); +} + +int +Cpm_jz4730_chip::pll_enabled() +{ + return _regs[Pll_control] & (1 << Pll_enabled); +} + +int +Cpm_jz4730_chip::pll_bypassed() +{ + return _regs[Pll_control] & (1 << Pll_bypassed); +} + +// Feedback (9-bit) multiplier. + +uint16_t +Cpm_jz4730_chip::get_multiplier() +{ + return ((_regs[Pll_control] & (0x1ff << Pll_multiplier)) >> Pll_multiplier) + 2; +} + +// Input (5-bit) divider. + +uint8_t +Cpm_jz4730_chip::get_input_division() +{ + return ((_regs[Pll_control] & (0x1f << Pll_input_division)) >> Pll_input_division) + 2; +} + +// Output divider. + +static uint8_t od[4] = {1, 2, 2, 4}; + +uint8_t +Cpm_jz4730_chip::get_output_division() +{ + return od[(_regs[Pll_control] & (0x03 << Pll_output_division)) >> Pll_output_division]; +} + +// General clock divider. + +static uint8_t cd[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + +uint8_t +Cpm_jz4730_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) +{ + uint8_t d = (_regs[reg] & mask) >> shift; + return (d < 10) ? cd[d] : 1; +} + +// CPU clock (CCLK) divider. + +uint8_t +Cpm_jz4730_chip::get_cpu_divider() +{ + return _get_divider(Clock_control, 0xf << Clock_cpu_divider, Clock_cpu_divider); +} + +// Fast peripheral clock (HCLK) divider. + +uint8_t +Cpm_jz4730_chip::get_hclock_divider() +{ + return _get_divider(Clock_control, 0xf << Clock_hclock_divider, Clock_hclock_divider); +} + +// Slow peripheral clock (PCLK) divider. + +uint8_t +Cpm_jz4730_chip::get_pclock_divider() +{ + return _get_divider(Clock_control, 0xf << Clock_pclock_divider, Clock_pclock_divider); +} + +// Memory clock (MCLK) divider. + +uint8_t +Cpm_jz4730_chip::get_memory_divider() +{ + return _get_divider(Clock_control, 0xf << Clock_memory_divider, Clock_memory_divider); +} + +// Clock source divider for MSC, I2S, LCD and USB. + +uint8_t +Cpm_jz4730_chip::get_source_divider() +{ + return 1; +} + +// LCD device clock divider. + +void +Cpm_jz4730_chip::set_lcd_device_divider(uint8_t division) +{ + if (division == 0) + division = 1; + + // NOTE: The vendor code (clock.c) bounds the divider at 16, but maybe this is + // NOTE: confused with the width of the bitfield which actually contains an + // NOTE: index for the clock divider value array (cd). + + else if (division > 16) + division = 16; + + // Obtain the divider or closest higher divider. + + int i; + + for (i = 0; i < 10; i++) + if (cd[i] >= division) break; + + _regs[Clock_control] = (_regs[Clock_control] & ~(0xf << Clock_lcd_divider)) | + (cd[i] << Clock_lcd_divider); +} + +// LCD pixel clock divider. + +uint16_t +Cpm_jz4730_chip::get_lcd_pixel_divider() +{ + return (_regs[Lcd_divider] >> Lcd_divider_value) + 1; +} + +void +Cpm_jz4730_chip::set_lcd_pixel_divider(uint16_t division) +{ + if (division == 0) + division = 1; + else if (division > 512) + division = 512; + + _regs[Lcd_divider] = (_regs[Lcd_divider] & ~(0x1ff << Lcd_divider_value)) | + ((division - 1) << Lcd_divider_value); +} + + + +uint32_t +Cpm_jz4730_chip::get_lcd_pixel_frequency() +{ + return get_output_frequency() / get_lcd_pixel_divider(); +} + +// Set the device and pixel frequencies, indicating the latter and +// providing the device:pixel frequency ratio. + +void +Cpm_jz4730_chip::set_lcd_frequencies(uint32_t pclk, uint8_t ratio) +{ + uint32_t out = get_output_frequency(), + lcd = pclk * ratio; + + set_lcd_pixel_divider(out / pclk); + + // Limit the device frequency to 150MHz. + + if (lcd > 150000000) lcd = 150000000; + + set_lcd_device_divider(out / lcd); +} + + + +// LCD clock control. + +void +Cpm_jz4730_chip::start_lcd() +{ + _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_lcd); +} + +void +Cpm_jz4730_chip::stop_lcd() +{ + _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_lcd); +} + + + +uint32_t +Cpm_jz4730_chip::get_pll_frequency() +{ + // Test for PLL enable and not PLL bypass. + + if (pll_enabled() && !pll_bypassed()) + return (_exclk_freq * get_multiplier()) / + (get_input_division() * get_output_division()); + else + return _exclk_freq; +} + +// Clock frequency for MSC, I2S, LCD and USB. + +uint32_t +Cpm_jz4730_chip::get_output_frequency() +{ + return get_pll_frequency() / get_source_divider(); +} + +void +Cpm_jz4730_chip::update_output_frequency() +{ + _regs[Clock_control] = _regs[Clock_control] | (1 << Clock_enable); +} + +// Clock frequency for the CPU. + +uint32_t Cpm_jz4730_chip::get_cpu_frequency() +{ + if (pll_enabled()) + return get_pll_frequency() / get_cpu_divider(); + else + return _exclk_freq; +} + +// Clock frequency for fast peripherals. + +uint32_t +Cpm_jz4730_chip::get_hclock_frequency() +{ + if (pll_enabled()) + return get_pll_frequency() / get_hclock_divider(); + else + return _exclk_freq; +} + +// Clock frequency for slow peripherals. + +uint32_t +Cpm_jz4730_chip::get_pclock_frequency() +{ + if (pll_enabled()) + return get_pll_frequency() / get_pclock_divider(); + else + return _exclk_freq; +} + +// Clock frequency for the memory. + +uint32_t +Cpm_jz4730_chip::get_memory_frequency() +{ + if (pll_enabled()) + return get_pll_frequency() / get_memory_divider(); + else + return _exclk_freq; +} + + + +// C language interface functions. + +void +*jz4730_cpm_init(l4_addr_t cpm_base) +{ + /* Initialise the clock and power management peripheral with the + register memory region and a 3.6864 MHz EXCLK frequency. */ + + return (void *) new Cpm_jz4730_chip(cpm_base, 3686400); +} + +int +jz4730_cpm_have_clock(void *cpm) +{ + return static_cast(cpm)->have_clock(); +} + +void +jz4730_cpm_start_clock(void *cpm) +{ + static_cast(cpm)->start_clock(); +} + +void +jz4730_cpm_start_lcd(void *cpm) +{ + static_cast(cpm)->start_lcd(); +} + +void +jz4730_cpm_stop_lcd(void *cpm) +{ + static_cast(cpm)->stop_lcd(); +} + +uint32_t +jz4730_cpm_get_cpu_frequency(void *cpm) +{ + return static_cast(cpm)->get_cpu_frequency(); +} + +uint32_t +jz4730_cpm_get_hclock_frequency(void *cpm) +{ + return static_cast(cpm)->get_hclock_frequency(); +} + +uint32_t +jz4730_cpm_get_output_frequency(void *cpm) +{ + return static_cast(cpm)->get_output_frequency(); +} + +uint32_t +jz4730_cpm_get_pclock_frequency(void *cpm) +{ + return static_cast(cpm)->get_pclock_frequency(); +} + +uint32_t +jz4730_cpm_get_memory_frequency(void *cpm) +{ + return static_cast(cpm)->get_memory_frequency(); +} + +uint16_t +jz4730_cpm_get_lcd_pixel_divider(void *cpm) +{ + return static_cast(cpm)->get_lcd_pixel_divider(); +} + +uint32_t +jz4730_cpm_get_lcd_pixel_frequency(void *cpm) +{ + return static_cast(cpm)->get_lcd_pixel_frequency(); +} + +void +jz4730_cpm_set_lcd_frequencies(void *cpm, uint32_t pclk, uint8_t ratio) +{ + static_cast(cpm)->set_lcd_frequencies(pclk, ratio); +} + +void +jz4730_cpm_update_output_frequency(void *cpm) +{ + static_cast(cpm)->update_output_frequency(); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/src/jz4740.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/src/jz4740.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,426 @@ +/* + * Clock and power management. This exposes the combined functionality + * provided by the jz4740 and related SoCs. The power management + * functionality could be exposed using a separate driver. + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include "cpm-jz4740.h" + + + +enum Regs : unsigned +{ + Clock_control = 0x000, // CPCCR + Low_power_control = 0x004, // LCR + Pll_control = 0x010, // CPPCR + Clock_gate = 0x020, // CLKGR + Sleep_control = 0x024, // SCR + I2s_divider = 0x060, // I2SCDR + Lcd_divider = 0x064, // LPCDR + Msc_divider = 0x068, // MSCCDR + Uhc_divider = 0x06c, // UHCCDR + Ssi_divider = 0x074, // SSICDR +}; + +enum Clock_bits : unsigned +{ + Clock_enable = 22, // CE + Clock_pllout_source = 21, // PCS + Clock_lcd_divider = 16, // LCD + Clock_memory_divider = 12, // MDIV + Clock_pclock_divider = 8, // PDIV (slow APB peripherals) + Clock_hclock_divider = 4, // HDIV (fast AHB peripherals) + Clock_cpu_divider = 0, // CDIV +}; + +enum Pll_bits : unsigned +{ + Pll_multiplier = 23, // PLLM + Pll_input_division = 18, // PLLN + Pll_output_division = 16, // PLLOD + Pll_stable = 10, // PLLS + Pll_bypassed = 9, // PLLBP + Pll_enabled = 8, // PLLEN +}; + +enum Clock_gate_bits : unsigned +{ + Clock_gate_lcd = 10, // LCD + Clock_gate_timer = 1, // TCU +}; + +enum Lcd_divider_bits : unsigned +{ + Lcd_divider_value = 0, +}; + + + +// If implemented as a Hw::Device, various properties would be +// initialised in the constructor and obtained from the device tree +// definitions. + +Cpm_jz4740_chip::Cpm_jz4740_chip(l4_addr_t addr, uint32_t exclk_freq) +: _exclk_freq(exclk_freq) +{ + _regs = new Hw::Mmio_register_block<32>(addr); + + // add_cid("cpm"); + // add_cid("cpm-jz4740"); + // register_property("exclk_freq", &_exclk_freq); +} + +// Clock/timer control. + +int +Cpm_jz4740_chip::have_clock() +{ + return !(_regs[Clock_gate] & (1 << Clock_gate_timer)); +} + +void +Cpm_jz4740_chip::start_clock() +{ + _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_timer); +} + +// PLL control. + +// Return whether the PLL is stable. + +int +Cpm_jz4740_chip::have_pll() +{ + return _regs[Pll_control] & (1 << Pll_stable); +} + +int +Cpm_jz4740_chip::pll_enabled() +{ + return _regs[Pll_control] & (1 << Pll_enabled); +} + +int +Cpm_jz4740_chip::pll_bypassed() +{ + return _regs[Pll_control] & (1 << Pll_bypassed); +} + +// Feedback (9-bit) multiplier. + +uint16_t +Cpm_jz4740_chip::get_multiplier() +{ + return ((_regs[Pll_control] & (0x1ff << Pll_multiplier)) >> Pll_multiplier) + 2; +} + +// Input (5-bit) divider. + +uint8_t +Cpm_jz4740_chip::get_input_division() +{ + return ((_regs[Pll_control] & (0x1f << Pll_input_division)) >> Pll_input_division) + 2; +} + +// Output divider. + +uint8_t +Cpm_jz4740_chip::get_output_division() +{ + uint8_t od[4] = {1, 2, 2, 4}; + return od[(_regs[Pll_control] & (0x03 << Pll_output_division)) >> Pll_output_division]; +} + +// General clock divider. + +uint8_t +Cpm_jz4740_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) +{ + uint8_t cd[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + uint8_t d = (_regs[reg] & mask) >> shift; + return (d < 10) ? cd[d] : 1; +} + +// CPU clock (CCLK) divider. + +uint8_t +Cpm_jz4740_chip::get_cpu_divider() +{ + return _get_divider(Clock_control, 0xf << Clock_cpu_divider, Clock_cpu_divider); +} + +// Fast peripheral clock (HCLK) divider. + +uint8_t +Cpm_jz4740_chip::get_hclock_divider() +{ + return _get_divider(Clock_control, 0xf << Clock_hclock_divider, Clock_hclock_divider); +} + +// Slow peripheral clock (PCLK) divider. + +uint8_t +Cpm_jz4740_chip::get_pclock_divider() +{ + return _get_divider(Clock_control, 0xf << Clock_pclock_divider, Clock_pclock_divider); +} + +// Memory clock (MCLK) divider. + +uint8_t +Cpm_jz4740_chip::get_memory_divider() +{ + return _get_divider(Clock_control, 0xf << Clock_memory_divider, Clock_memory_divider); +} + +// Clock source divider for MSC, I2S, LCD and USB. + +uint8_t +Cpm_jz4740_chip::get_source_divider() +{ + return _regs[Clock_control] & (1 << Clock_pllout_source) ? 1 : 2; +} + +// LCD device clock divider. + +void +Cpm_jz4740_chip::set_lcd_device_divider(uint8_t division) +{ + if (division == 0) + division = 1; + else if (division > 32) + division = 32; + + _regs[Clock_control] = (_regs[Clock_control] & ~(0x1f << Clock_lcd_divider)) | + ((division - 1) << Clock_lcd_divider); +} + +// LCD pixel clock divider. + +uint16_t +Cpm_jz4740_chip::get_lcd_pixel_divider() +{ + return (_regs[Lcd_divider] >> Lcd_divider_value) + 1; +} + +void +Cpm_jz4740_chip::set_lcd_pixel_divider(uint16_t division) +{ + if (division == 0) + division = 1; + else if (division > 2048) + division = 2048; + + _regs[Lcd_divider] = (_regs[Lcd_divider] & ~(0x7ff << Lcd_divider_value)) | + ((division - 1) << Lcd_divider_value); +} + + + +uint32_t +Cpm_jz4740_chip::get_lcd_pixel_frequency() +{ + return get_output_frequency() / get_lcd_pixel_divider(); +} + +// Set the device and pixel frequencies, indicating the latter and +// providing the device:pixel frequency ratio. + +void +Cpm_jz4740_chip::set_lcd_frequencies(uint32_t pclk, uint8_t ratio) +{ + uint32_t out = get_output_frequency(), + lcd = pclk * ratio; + + set_lcd_pixel_divider(out / pclk); + + // Limit the device frequency to 150MHz. + + if (lcd > 150000000) lcd = 150000000; + + set_lcd_device_divider(out / lcd); +} + + + +// LCD clock control. + +void +Cpm_jz4740_chip::start_lcd() +{ + _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_lcd); +} + +void +Cpm_jz4740_chip::stop_lcd() +{ + _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_lcd); +} + + + +uint32_t +Cpm_jz4740_chip::get_pll_frequency() +{ + // Test for PLL enable and not PLL bypass. + + if (pll_enabled() && !pll_bypassed()) + return (_exclk_freq * get_multiplier()) / + (get_input_division() * get_output_division()); + else + return _exclk_freq; +} + +// Clock frequency for MSC, I2S, LCD and USB. + +uint32_t +Cpm_jz4740_chip::get_output_frequency() +{ + return get_pll_frequency() / get_source_divider(); +} + +void +Cpm_jz4740_chip::update_output_frequency() +{ + _regs[Clock_control] = _regs[Clock_control] | (1 << Clock_enable); +} + +// Clock frequency for the CPU. + +uint32_t Cpm_jz4740_chip::get_cpu_frequency() +{ + return get_pll_frequency() / get_cpu_divider(); +} + +// Clock frequency for fast peripherals. + +uint32_t +Cpm_jz4740_chip::get_hclock_frequency() +{ + return get_pll_frequency() / get_hclock_divider(); +} + +// Clock frequency for slow peripherals. + +uint32_t +Cpm_jz4740_chip::get_pclock_frequency() +{ + return get_pll_frequency() / get_pclock_divider(); +} + +// Clock frequency for the memory. + +uint32_t +Cpm_jz4740_chip::get_memory_frequency() +{ + return get_pll_frequency() / get_memory_divider(); +} + + + +// C language interface functions. + +void +*jz4740_cpm_init(l4_addr_t cpm_base) +{ + /* Initialise the clock and power management peripheral with the + register memory region and a 12MHz EXCLK frequency. */ + + return (void *) new Cpm_jz4740_chip(cpm_base, 12000000); +} + +int +jz4740_cpm_have_clock(void *cpm) +{ + return static_cast(cpm)->have_clock(); +} + +void +jz4740_cpm_start_clock(void *cpm) +{ + static_cast(cpm)->start_clock(); +} + +void +jz4740_cpm_start_lcd(void *cpm) +{ + static_cast(cpm)->start_lcd(); +} + +void +jz4740_cpm_stop_lcd(void *cpm) +{ + static_cast(cpm)->stop_lcd(); +} + +uint32_t +jz4740_cpm_get_cpu_frequency(void *cpm) +{ + return static_cast(cpm)->get_cpu_frequency(); +} + +uint32_t +jz4740_cpm_get_hclock_frequency(void *cpm) +{ + return static_cast(cpm)->get_hclock_frequency(); +} + +uint32_t +jz4740_cpm_get_output_frequency(void *cpm) +{ + return static_cast(cpm)->get_output_frequency(); +} + +uint32_t +jz4740_cpm_get_pclock_frequency(void *cpm) +{ + return static_cast(cpm)->get_pclock_frequency(); +} + +uint32_t +jz4740_cpm_get_memory_frequency(void *cpm) +{ + return static_cast(cpm)->get_memory_frequency(); +} + +uint16_t +jz4740_cpm_get_lcd_pixel_divider(void *cpm) +{ + return static_cast(cpm)->get_lcd_pixel_divider(); +} + +uint32_t +jz4740_cpm_get_lcd_pixel_frequency(void *cpm) +{ + return static_cast(cpm)->get_lcd_pixel_frequency(); +} + +void +jz4740_cpm_set_lcd_frequencies(void *cpm, uint32_t pclk, uint8_t ratio) +{ + static_cast(cpm)->set_lcd_frequencies(pclk, ratio); +} + +void +jz4740_cpm_update_output_frequency(void *cpm) +{ + static_cast(cpm)->update_output_frequency(); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/cpm/src/jz4780.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/cpm/src/jz4780.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,918 @@ +/* + * Clock and power management. This exposes the combined functionality + * provided by the jz4780 and related SoCs. The power management + * functionality could be exposed using a separate driver. + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include "cpm-jz4780.h" + + + +enum Regs : unsigned +{ + Clock_control = 0x000, // CPCCR + Low_power_control = 0x004, // LCR + Pll_control = 0x00c, // CPPCR + Pll_control_A = 0x010, // CPAPCR + Pll_control_M = 0x014, // CPMPCR + Pll_control_E = 0x018, // CPEPCR + Pll_control_V = 0x01c, // CPVPCR + Clock_gate0 = 0x020, // CLKGR0 + Clock_gate1 = 0x028, // CLKGR1 + Sleep_control = 0x024, // OPCR (oscillator and power control) + Ddr_divider = 0x02c, // DDRCDR + I2s_divider0 = 0x060, // I2SCDR + I2s_divider1 = 0x0a0, // I2S1CDR + Lcd_divider0 = 0x054, // LP0CDR + Lcd_divider1 = 0x064, // LP1CDR + Msc_divider0 = 0x068, // MSC0CDR + Msc_divider1 = 0x0a4, // MSC1CDR + Msc_divider2 = 0x0a8, // MSC2CDR + Uhc_divider = 0x06c, // UHCCDR + Ssi_divider = 0x074, // SSICDR +}; + +enum Clock_bits : unsigned +{ + Clock_enable = 22, // CE_CPU + Clock_pclock_divider = 16, // PDIV (slow APB peripherals) + Clock_hclock2_divider = 12, // H2DIV (fast AHB peripherals) + Clock_hclock0_divider = 8, // H0DIV (fast AHB peripherals) + Clock_cpu_divider = 0, // CDIV +}; + +enum Pll_bits : unsigned +{ + Pll_multiplier = 19, // xPLLM + Pll_input_division = 13, // xPLLN + Pll_output_division = 9, // xPLLOD + Pll_stable = 4, // xPLL_ON + Pll_bypassed = 1, // xPLLBP + Pll_enabled = 0, // xPLLEN +}; + +enum Clock_source_bits : unsigned +{ + Clock_source_main = 30, // SEL_SRC (output to SCLK_A) + Clock_source_cpu = 28, // SEL_CPLL (output to CCLK) + Clock_source_hclock0 = 26, // SEL_H0PLL (output to AHB0) + Clock_source_hclock2 = 24, // SEL_H2PLL (output to AHB2) + Clock_source_ddr = 30, // DCS + Clock_source_i2s = 31, // I2CS + Clock_source_lcd = 30, // LPCS +}; + +enum Clock_sources : unsigned +{ + Source_pll_A = 1, // APLL + Source_external = 2, // EXCLK + Source_realtime = 3, // RTCLK + Source_main_frequency = 1, // SCLK_A + Source_pll_M = 2, // MPLL + Source_pll_E = 3, // EPLL + Source_pll_V = 3, // VPLL +}; + +enum Clock_gate_bits : unsigned +{ + Clock_gate_lcd = 28, // LCD (in CLKGR0) + Clock_gate_tve = 27, // TVE (in CLKGR0) + Clock_gate_smb4 = 12, // SMB4 (in CLKGR1) + Clock_gate_smb3 = 0, // SMB3 (in CLKGR1) + Clock_gate_smb2 = 25, // SMB2 (in CLKGR0) + Clock_gate_smb1 = 6, // SMB2 (in CLKGR0) + Clock_gate_smb0 = 5, // SMB2 (in CLKGR0) +}; + +enum Clock_gate_regs : unsigned +{ + Clock_gate_reg_smb4 = Clock_gate1, + Clock_gate_reg_smb3 = Clock_gate1, + Clock_gate_reg_smb2 = Clock_gate0, + Clock_gate_reg_smb1 = Clock_gate0, + Clock_gate_reg_smb0 = Clock_gate0, +}; + +enum Divider_bits : unsigned +{ + Ddr_divider_value = 0, // DDRCDR + Lcd_divider_value = 0, // LPCDR +}; + +enum Lcd_clock_bits : unsigned +{ + Lcd_change_enable = 0x1000, // CE_LCD + Lcd_change_busy = 0x0800, // LCD_BUSY + Lcd_clock_stop = 0x0400, // LCD_STOP +}; + + + +// If implemented as a Hw::Device, various properties would be +// initialised in the constructor and obtained from the device tree +// definitions. + +Cpm_jz4780_chip::Cpm_jz4780_chip(l4_addr_t addr, uint32_t exclk_freq, uint32_t rtclk_freq) +: _exclk_freq(exclk_freq), _rtclk_freq(rtclk_freq) +{ + _regs = new Hw::Mmio_register_block<32>(addr); + + // add_cid("cpm"); + // add_cid("cpm-jz4780"); + // register_property("exclk_freq", &_exclk_freq); +} + +// Clock/timer control. +// NOTE: For the time being, assume that the system is configured. + +int +Cpm_jz4780_chip::have_clock() +{ + // return !(_regs[Clock_gate] & (1 << Clock_gate_timer)); + return 1; +} + +void +Cpm_jz4780_chip::start_clock() +{ + // _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_timer); +} + + + +// Utility methods. + +uint32_t +Cpm_jz4780_chip::get_field(uint32_t reg, uint32_t mask, uint8_t shift) +{ + return (_regs[reg] & (mask << shift)) >> shift; +} + +void +Cpm_jz4780_chip::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) +{ + _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); +} + +// General clock divider access. + +uint8_t +Cpm_jz4780_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) +{ + uint8_t d = get_field(reg, mask, shift); + + // NOTE: Value 14 stops the clock, 15 presumably resumes the clock. + + return (d < 14) ? d + 1 : 1; +} + + + +// PLL control. + +// Return whether the PLL is stable. + +int +Cpm_jz4780_chip::have_pll(uint32_t pll_reg) +{ + return _regs[pll_reg] & (1 << Pll_stable); +} + +int +Cpm_jz4780_chip::pll_enabled(uint32_t pll_reg) +{ + return _regs[pll_reg] & (1 << Pll_enabled); +} + +int +Cpm_jz4780_chip::pll_bypassed(uint32_t pll_reg) +{ + return _regs[pll_reg] & (1 << Pll_bypassed); +} + +// Feedback (13-bit) multiplier. + +uint16_t +Cpm_jz4780_chip::get_multiplier(uint32_t pll_reg) +{ + return get_field(pll_reg, 0x1fff, Pll_multiplier) + 1; +} + +void +Cpm_jz4780_chip::set_multiplier(uint32_t pll_reg, uint16_t multiplier) +{ + set_field(pll_reg, 0x1fff, Pll_multiplier, multiplier - 1); +} + +// Input (6-bit) divider. + +uint8_t +Cpm_jz4780_chip::get_input_division(uint32_t pll_reg) +{ + return get_field(pll_reg, 0x3f, Pll_input_division) + 1; +} + +void +Cpm_jz4780_chip::set_input_division(uint32_t pll_reg, uint8_t divider) +{ + set_field(pll_reg, 0x3f, Pll_input_division, divider - 1); +} + +// Output divider. + +uint8_t +Cpm_jz4780_chip::get_output_division(uint32_t pll_reg) +{ + uint8_t d = get_field(pll_reg, 0x0f, Pll_output_division); + + // Zero yields a division of one. Otherwise enforce even results. + + return d == 0 ? 1 : (d + 1) & 0x0e; +} + +void +Cpm_jz4780_chip::set_output_division(uint32_t pll_reg, uint8_t divider) +{ + uint8_t d = divider <= 1 ? 0 : (divider & 0x0e) - 1; + + set_field(pll_reg, 0x0f, Pll_output_division, d); +} + +uint32_t +Cpm_jz4780_chip::get_pll_frequency(uint32_t pll_reg) +{ + // Test for PLL enable and not PLL bypass. + + if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) + return (_exclk_freq * get_multiplier(pll_reg)) / + (get_input_division(pll_reg) * get_output_division(pll_reg)); + else + return _exclk_freq; +} + +void +Cpm_jz4780_chip::set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) +{ + set_multiplier(pll_reg, multiplier); + set_input_division(pll_reg, in_divider); + set_output_division(pll_reg, out_divider); + + if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) + while (!have_pll(pll_reg)); +} + + + +// CPU clock (CCLK) divider. + +uint8_t +Cpm_jz4780_chip::get_cpu_divider() +{ + return _get_divider(Clock_control, 0xf, Clock_cpu_divider); +} + +// Fast peripheral clock (H0CLK) divider. + +uint8_t +Cpm_jz4780_chip::get_hclock0_divider() +{ + return _get_divider(Clock_control, 0xf, Clock_hclock0_divider); +} + +// Fast peripheral clock (H2CLK) divider. + +uint8_t +Cpm_jz4780_chip::get_hclock2_divider() +{ + return _get_divider(Clock_control, 0xf, Clock_hclock2_divider); +} + +// Slow peripheral clock (PCLK) divider. + +uint8_t +Cpm_jz4780_chip::get_pclock_divider() +{ + return _get_divider(Clock_control, 0xf, Clock_pclock_divider); +} + +// LCD clock (LPCLK) divider for LCD0 pixel clock. + +uint8_t +Cpm_jz4780_chip::get_lcd_pixel_divider() +{ + return get_field(Lcd_divider0, 0xff, Lcd_divider_value) + 1; +} + +// Memory clock (DDR_CLK) divider. + +uint8_t +Cpm_jz4780_chip::get_memory_divider() +{ + return _get_divider(Ddr_divider, 0xf, Ddr_divider_value); +} + +// LCD pixel clock divider. +// NOTE: This only supports the first LCD peripheral. + +void +Cpm_jz4780_chip::set_lcd_pixel_divider(uint16_t division) +{ + if ((division < 1) || (division > 256)) + return; + + // Enable change. + + _regs[Lcd_divider0] = _regs[Lcd_divider0] | Lcd_change_enable; + + // Set the divider. + + set_field(Lcd_divider0, 0xff, Lcd_divider_value, division - 1); + + // Restart clock and disable change. + + while (_regs[Lcd_divider0] & Lcd_change_busy); + _regs[Lcd_divider0] = _regs[Lcd_divider0] & ~Lcd_change_enable; +} + + + +// Clock gating control. + +void +Cpm_jz4780_chip::start_lcd() +{ + _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd); +} + +void +Cpm_jz4780_chip::stop_lcd() +{ + _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd); +} + +void +Cpm_jz4780_chip::_update_i2c(uint8_t channel, int enable) +{ + uint8_t bit; + uint32_t reg; + switch (channel) + { + case 0: bit = Clock_gate_smb0; reg = Clock_gate_reg_smb0; break; + case 1: bit = Clock_gate_smb1; reg = Clock_gate_reg_smb1; break; + case 2: bit = Clock_gate_smb2; reg = Clock_gate_reg_smb2; break; + case 3: bit = Clock_gate_smb3; reg = Clock_gate_reg_smb3; break; + case 4: bit = Clock_gate_smb4; reg = Clock_gate_reg_smb4; break; + default: return; + } + if (enable) + _regs[reg] = _regs[reg] & ~(1 << bit); + else + _regs[reg] = _regs[reg] | (1 << bit); +} + +void +Cpm_jz4780_chip::start_i2c(uint8_t channel) +{ + _update_i2c(channel, 1); +} + +void +Cpm_jz4780_chip::stop_i2c(uint8_t channel) +{ + _update_i2c(channel, 0); +} + + + +// Clock sources. + +uint8_t +Cpm_jz4780_chip::get_memory_source() +{ + return get_field(Ddr_divider, 0x3, Clock_source_ddr); +} + +uint32_t +Cpm_jz4780_chip::get_memory_source_frequency() +{ + switch (get_memory_source()) + { + case Source_main_frequency: + return get_main_frequency(); + case Source_pll_M: + return get_pll_frequency(Pll_control_M); + default: + return 0; + } +} + +uint8_t +Cpm_jz4780_chip::get_cpu_source() +{ + return get_field(Clock_control, 0x3, Clock_source_cpu); +} + +uint32_t +Cpm_jz4780_chip::get_cpu_source_frequency() +{ + switch (get_cpu_source()) + { + case Source_main_frequency: + return get_main_frequency(); + case Source_pll_M: + return get_pll_frequency(Pll_control_M); + case Source_pll_E: + return get_pll_frequency(Pll_control_E); + default: + return 0; + } +} + +uint8_t +Cpm_jz4780_chip::get_hclock0_source() +{ + return get_field(Clock_control, 0x3, Clock_source_hclock0); +} + +uint32_t +Cpm_jz4780_chip::get_hclock0_source_frequency() +{ + switch (get_hclock0_source()) + { + case Source_main_frequency: + return get_main_frequency(); + case Source_pll_M: + return get_pll_frequency(Pll_control_M); + case Source_pll_E: + return get_pll_frequency(Pll_control_E); + default: + return 0; + } +} + +uint8_t +Cpm_jz4780_chip::get_hclock2_source() +{ + return get_field(Clock_control, 0x3, Clock_source_hclock2); +} + +uint32_t +Cpm_jz4780_chip::get_hclock2_source_frequency() +{ + switch (get_hclock2_source()) + { + case Source_main_frequency: + return get_main_frequency(); + case Source_pll_M: + return get_pll_frequency(Pll_control_M); + case Source_realtime: + return _rtclk_freq; // "TCK" in the manual, RTCLK in Linux driver code + default: + return 0; + } +} + +void +Cpm_jz4780_chip::set_hclock2_source(uint8_t source) +{ + set_field(Clock_control, 0x3, Clock_source_hclock2, source); +} + +uint8_t +Cpm_jz4780_chip::get_lcd_source() +{ + return get_field(Lcd_divider0, 0x3, Clock_source_lcd); +} + +uint32_t +Cpm_jz4780_chip::get_lcd_source_frequency() +{ + switch (get_lcd_source()) + { + case Source_main_frequency: + return get_main_frequency(); + case Source_pll_M: + return get_pll_frequency(Pll_control_M); + case Source_pll_V: + return get_pll_frequency(Pll_control_V); + default: + return 0; + } +} + +void +Cpm_jz4780_chip::set_lcd_source(uint8_t source) +{ + // Stop clock and enable change. + + _regs[Lcd_divider0] = _regs[Lcd_divider0] | Lcd_change_enable | Lcd_clock_stop; + + // Set the source. + + set_field(Lcd_divider0, 0x03, Clock_source_lcd, source); + + // Restart clock and disable change. + + while (_regs[Lcd_divider0] & Lcd_change_busy); + _regs[Lcd_divider0] = _regs[Lcd_divider0] & ~(Lcd_change_enable | Lcd_clock_stop); +} + +uint8_t +Cpm_jz4780_chip::get_pclock_source() +{ + return get_hclock2_source(); +} + +uint32_t +Cpm_jz4780_chip::get_pclock_source_frequency() +{ + return get_hclock2_source_frequency(); +} + +void +Cpm_jz4780_chip::set_pclock_source(uint8_t source) +{ + set_hclock2_source(source); +} + + + +// Source frequency, used by various clock sources. + +uint8_t +Cpm_jz4780_chip::get_main_source() +{ + return get_field(Clock_control, 0x3, Clock_source_main); +} + +uint32_t +Cpm_jz4780_chip::get_main_frequency() +{ + switch (get_main_source()) + { + case Source_pll_A: + return get_pll_frequency(Pll_control_A); + case Source_external: + return _exclk_freq; + case Source_realtime: + return _rtclk_freq; + default: + return 0; + } +} + +// Clock frequency for the CPU. + +uint32_t +Cpm_jz4780_chip::get_cpu_frequency() +{ + return get_cpu_source_frequency() / get_cpu_divider(); +} + +// Clock frequency for fast peripherals. + +uint32_t +Cpm_jz4780_chip::get_hclock0_frequency() +{ + return get_hclock0_source_frequency() / get_hclock0_divider(); +} + +// Clock frequency for fast peripherals. + +uint32_t +Cpm_jz4780_chip::get_hclock2_frequency() +{ + return get_hclock2_source_frequency() / get_hclock2_divider(); +} + +// Clock frequency for slow peripherals. + +uint32_t +Cpm_jz4780_chip::get_pclock_frequency() +{ + return get_pclock_source_frequency() / get_pclock_divider(); +} + +// Clock frequency for the LCD0 controller. + +uint32_t +Cpm_jz4780_chip::get_lcd_pixel_frequency() +{ + return get_lcd_source_frequency() / get_lcd_pixel_divider(); +} + +// Clock frequency for the memory. + +uint32_t +Cpm_jz4780_chip::get_memory_frequency() +{ + return get_memory_source_frequency() / get_memory_divider(); +} + +uint32_t +Cpm_jz4780_chip::get_apll_frequency() +{ + return get_pll_frequency(Pll_control_A); +} + +uint32_t +Cpm_jz4780_chip::get_epll_frequency() +{ + return get_pll_frequency(Pll_control_E); +} + +uint32_t +Cpm_jz4780_chip::get_mpll_frequency() +{ + return get_pll_frequency(Pll_control_M); +} + +uint32_t +Cpm_jz4780_chip::get_vpll_frequency() +{ + return get_pll_frequency(Pll_control_V); +} + + + +// Set the pixel frequency. +// Unlike the jz4740, HCLK/AHB0 is used as the device frequency, with the pixel +// frequency being based on the selected clock source (SCLK_A, MPLL or VPLL). + +void +Cpm_jz4780_chip::set_lcd_pixel_frequency(uint32_t pclk) +{ + // Switch to the video PLL and attempt to set the divider. + + set_lcd_source(Source_pll_V); + set_lcd_pixel_divider(get_lcd_source_frequency() / pclk); +} + +// NOTE: Compatibility method. Probably needs reviewing. + +void +Cpm_jz4780_chip::set_lcd_frequencies(uint32_t pclk, uint8_t ratio) +{ + (void) ratio; + set_lcd_pixel_frequency(pclk); +} + +// NOTE: Empty method for compatibility. + +void +Cpm_jz4780_chip::update_output_frequency() +{ +} + + + +// C language interface functions. + +void +*jz4780_cpm_init(l4_addr_t cpm_base) +{ + /* Initialise the clock and power management peripheral with the + register memory region and a 48MHz EXCLK frequency. */ + + return (void *) new Cpm_jz4780_chip(cpm_base, 48000000, 32768); +} + +int +jz4780_cpm_have_clock(void *cpm) +{ + return static_cast(cpm)->have_clock(); +} + +void +jz4780_cpm_start_clock(void *cpm) +{ + static_cast(cpm)->start_clock(); +} + + + +void +jz4780_cpm_start_lcd(void *cpm) +{ + static_cast(cpm)->start_lcd(); +} + +void +jz4780_cpm_stop_lcd(void *cpm) +{ + static_cast(cpm)->stop_lcd(); +} + + + +uint8_t +jz4780_cpm_get_cpu_divider(void *cpm) +{ + return static_cast(cpm)->get_cpu_divider(); +} + +uint8_t +jz4780_cpm_get_hclock0_divider(void *cpm) +{ + return static_cast(cpm)->get_hclock0_divider(); +} + +uint8_t +jz4780_cpm_get_hclock2_divider(void *cpm) +{ + return static_cast(cpm)->get_hclock2_divider(); +} + +uint8_t +jz4780_cpm_get_lcd_pixel_divider(void *cpm) +{ + return static_cast(cpm)->get_lcd_pixel_divider(); +} + +uint8_t +jz4780_cpm_get_memory_divider(void *cpm) +{ + return static_cast(cpm)->get_memory_divider(); +} + +uint8_t +jz4780_cpm_get_pclock_divider(void *cpm) +{ + return static_cast(cpm)->get_pclock_divider(); +} + + + +uint8_t +jz4780_cpm_get_hclock0_source(void *cpm) +{ + return static_cast(cpm)->get_hclock0_source(); +} + +uint8_t +jz4780_cpm_get_hclock2_source(void *cpm) +{ + return static_cast(cpm)->get_hclock2_source(); +} + +uint8_t +jz4780_cpm_get_lcd_source(void *cpm) +{ + return static_cast(cpm)->get_lcd_source(); +} + +uint8_t +jz4780_cpm_get_memory_source(void *cpm) +{ + return static_cast(cpm)->get_memory_source(); +} + +uint8_t +jz4780_cpm_get_pclock_source(void *cpm) +{ + return static_cast(cpm)->get_pclock_source(); +} + +void +jz4780_cpm_set_pclock_source(void *cpm, uint8_t source) +{ + static_cast(cpm)->set_pclock_source(source); +} + + + +uint32_t +jz4780_cpm_get_hclock0_source_frequency(void *cpm) +{ + return static_cast(cpm)->get_hclock0_source_frequency(); +} + +uint32_t +jz4780_cpm_get_hclock2_source_frequency(void *cpm) +{ + return static_cast(cpm)->get_hclock2_source_frequency(); +} + +uint32_t +jz4780_cpm_get_lcd_source_frequency(void *cpm) +{ + return static_cast(cpm)->get_lcd_source_frequency(); +} + +uint32_t +jz4780_cpm_get_memory_source_frequency(void *cpm) +{ + return static_cast(cpm)->get_memory_source_frequency(); +} + +uint32_t +jz4780_cpm_get_pclock_source_frequency(void *cpm) +{ + return static_cast(cpm)->get_pclock_source_frequency(); +} + + + +uint8_t +jz4780_cpm_get_main_source(void *cpm) +{ + return static_cast(cpm)->get_main_source(); +} + +uint32_t +jz4780_cpm_get_main_frequency(void *cpm) +{ + return static_cast(cpm)->get_main_frequency(); +} + +uint32_t +jz4780_cpm_get_cpu_frequency(void *cpm) +{ + return static_cast(cpm)->get_cpu_frequency(); +} + +uint32_t +jz4780_cpm_get_hclock0_frequency(void *cpm) +{ + return static_cast(cpm)->get_hclock0_frequency(); +} + +uint32_t +jz4780_cpm_get_hclock2_frequency(void *cpm) +{ + return static_cast(cpm)->get_hclock2_frequency(); +} + +uint32_t +jz4780_cpm_get_lcd_pixel_frequency(void *cpm) +{ + return static_cast(cpm)->get_lcd_pixel_frequency(); +} + +uint32_t +jz4780_cpm_get_memory_frequency(void *cpm) +{ + return static_cast(cpm)->get_memory_frequency(); +} + +uint32_t +jz4780_cpm_get_pclock_frequency(void *cpm) +{ + return static_cast(cpm)->get_pclock_frequency(); +} + +uint32_t +jz4780_cpm_get_apll_frequency(void *cpm) +{ + return static_cast(cpm)->get_apll_frequency(); +} + +uint32_t +jz4780_cpm_get_epll_frequency(void *cpm) +{ + return static_cast(cpm)->get_epll_frequency(); +} + +uint32_t +jz4780_cpm_get_mpll_frequency(void *cpm) +{ + return static_cast(cpm)->get_mpll_frequency(); +} + +uint32_t +jz4780_cpm_get_vpll_frequency(void *cpm) +{ + return static_cast(cpm)->get_vpll_frequency(); +} + + + +void +jz4780_cpm_set_lcd_pixel_frequency(void *cpm, uint32_t pclk) +{ + static_cast(cpm)->set_lcd_pixel_frequency(pclk); +} + +void +jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) +{ + static_cast(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/include/gpio-jz4730.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/include/gpio-jz4730.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,188 @@ +/* + * GPIO driver for Ingenic JZ4730. + * (See below for additional copyright and licensing notices.) + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Subject to other copyrights, being derived from the bcm2835.cc and + * omap.cc GPIO driver implementations. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#pragma once + +#include +#include +#include +#include "gpio.h" + + + +#ifdef __cplusplus + +#include + +// GPIO device control. + +class Gpio_jz4730_irq_pin : public Hw::Gpio_irq_pin +{ + unsigned _pin; + Hw::Register_block<32> _regs; + + // Convenience method for obtaining the bit corresponding to a pin. + + l4_uint32_t _pin_bit(unsigned pin) + { return 1 << (pin & 31); } + + void write_reg_pin(unsigned reg); + + // Convenience methods for clearing and setting bits in the absence of + // dedicated registers. + + void clear_reg_pin(unsigned reg); + void set_reg_pin(unsigned reg); + void clear_reg_pins(uint32_t reg_upper, uint32_t reg_lower); + void set_reg_pins(uint32_t reg_upper, uint32_t reg_lower, uint8_t value); + +public: + Gpio_jz4730_irq_pin(unsigned pin, Hw::Register_block<32> const ®s); + + void do_mask(); + void do_unmask(); + bool do_set_mode(unsigned mode); + int clear(); + bool enabled(); +}; + +class Gpio_jz4730_chip : public Hw::Gpio_chip +{ +private: + Hw::Register_block<32> _regs; + + l4_addr_t _start, _end; + unsigned _nr_pins; + + // Convenience method for obtaining the bit corresponding to a pin. + + l4_uint32_t _pin_bit(unsigned pin) + { return 1 << (pin & 31); } + + // Convenience method for obtaining the bit position of a pin. + + unsigned _pin_shift(unsigned pin) + { return pin % 32; } + + // Permit only "aligned" accesses to registers. + + unsigned _reg_offset_check(unsigned pin_offset) const + { + switch (pin_offset) + { + case 0: + return 0; + + default: + throw -L4_EINVAL; + } + } + + // General configuration register updates. + + void _config(unsigned bitmap, unsigned mode); + + // General pull-up register updates. + + void _config_pull(unsigned bitmap, unsigned mode); + + // General pad register updates. + + void _config_pad(unsigned bitmap, unsigned func, unsigned value); + +public: + Gpio_jz4730_chip(l4_addr_t start, l4_addr_t end, + unsigned nr_pins); + + // Obtain the number of pins. + + unsigned nr_pins() const { return _nr_pins; } + + // Unnecessary operations. + + void request(unsigned) {} + void free(unsigned) {} + + // Configuration methods. + + void setup(unsigned pin, unsigned mode, int value = 0); + void config_pull(unsigned pin, unsigned mode); + void config_pad(unsigned pin, unsigned func, unsigned value); + void config_get(unsigned pin, unsigned reg, unsigned *value); + + // Multiple pin configuration methods. + + void multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues = 0); + void multi_config_pull(Pin_slice const &mask, unsigned mode); + void multi_config_pad(Pin_slice const &mask, unsigned func, unsigned value = 0); + void multi_set(Pin_slice const &mask, unsigned data); + unsigned multi_get(unsigned offset); + + // IRQ pin configuration. + + Hw::Gpio_irq_pin *get_irq(unsigned pin); + + // Pin/port data methods. + + int get(unsigned pin); + void set(unsigned pin, int value); + +private: + void config(unsigned pin, unsigned mode); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4730_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins); + +void jz4730_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value); +void jz4730_gpio_config_pull(void *gpio, unsigned pin, unsigned mode); +void jz4730_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value); +void jz4730_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value); + +void jz4730_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues); +void jz4730_gpio_multi_config_pull(void *gpio, Pin_slice const *mask, unsigned mode); +void jz4730_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value); +void jz4730_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data); +unsigned jz4730_gpio_multi_get(void *gpio, unsigned offset); + +int jz4730_gpio_get(void *gpio, unsigned pin); +void jz4730_gpio_set(void *gpio, unsigned pin, int value); + +void *jz4730_gpio_get_irq(void *gpio, unsigned pin); +bool jz4730_gpio_irq_set_mode(void *gpio_irq, unsigned mode); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/include/gpio-jz4740.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/include/gpio-jz4740.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,180 @@ +/* + * GPIO driver for Ingenic JZ4740. + * (See below for additional copyright and licensing notices.) + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Subject to other copyrights, being derived from the bcm2835.cc and + * omap.cc GPIO driver implementations. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#pragma once + +#include +#include +#include +#include "gpio.h" + + + +#ifdef __cplusplus + +#include + +// GPIO device control. + +class Gpio_jz4740_irq_pin : public Hw::Gpio_irq_pin +{ + unsigned _pin; + Hw::Register_block<32> _regs; + + // Convenience method for obtaining the bit corresponding to a pin. + + l4_uint32_t _pin_bit(unsigned pin) + { return 1 << (pin & 31); } + + void write_reg_pin(unsigned reg); + +public: + Gpio_jz4740_irq_pin(unsigned pin, Hw::Register_block<32> const ®s); + + void do_mask(); + void do_unmask(); + bool do_set_mode(unsigned mode); + int clear(); + bool enabled(); +}; + +class Gpio_jz4740_chip : public Hw::Gpio_chip +{ +private: + Hw::Register_block<32> _regs; + + l4_addr_t _start, _end; + unsigned _nr_pins; + + // Convenience method for obtaining the bit corresponding to a pin. + + l4_uint32_t _pin_bit(unsigned pin) + { return 1 << (pin & 31); } + + // Convenience method for obtaining the bit position of a pin. + + unsigned _pin_shift(unsigned pin) + { return pin % 32; } + + // Permit only "aligned" accesses to registers. + + unsigned _reg_offset_check(unsigned pin_offset) const + { + switch (pin_offset) + { + case 0: + return 0; + + default: + throw -L4_EINVAL; + } + } + + // General configuration register updates. + + void _config(unsigned bitmap, unsigned mode); + + // General pull-up register updates. + + void _config_pull(unsigned bitmap, unsigned mode); + + // General pad register updates. + + void _config_pad(unsigned bitmap, unsigned func, unsigned value); + +public: + Gpio_jz4740_chip(l4_addr_t start, l4_addr_t end, + unsigned nr_pins); + + // Obtain the number of pins. + + unsigned nr_pins() const { return _nr_pins; } + + // Unnecessary operations. + + void request(unsigned) {} + void free(unsigned) {} + + // Configuration methods. + + void setup(unsigned pin, unsigned mode, int value = 0); + void config_pull(unsigned pin, unsigned mode); + void config_pad(unsigned pin, unsigned func, unsigned value); + void config_get(unsigned pin, unsigned reg, unsigned *value); + + // Multiple pin configuration methods. + + void multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues = 0); + void multi_config_pull(Pin_slice const &mask, unsigned mode); + void multi_config_pad(Pin_slice const &mask, unsigned func, unsigned value = 0); + void multi_set(Pin_slice const &mask, unsigned data); + unsigned multi_get(unsigned offset); + + // IRQ pin configuration. + + Hw::Gpio_irq_pin *get_irq(unsigned pin); + + // Pin/port data methods. + + int get(unsigned pin); + void set(unsigned pin, int value); + +private: + void config(unsigned pin, unsigned mode); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4740_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins); + +void jz4740_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value); +void jz4740_gpio_config_pull(void *gpio, unsigned pin, unsigned mode); +void jz4740_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value); +void jz4740_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value); + +void jz4740_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues); +void jz4740_gpio_multi_config_pull(void *gpio, Pin_slice const *mask, unsigned mode); +void jz4740_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value); +void jz4740_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data); +unsigned jz4740_gpio_multi_get(void *gpio, unsigned offset); + +int jz4740_gpio_get(void *gpio, unsigned pin); +void jz4740_gpio_set(void *gpio, unsigned pin, int value); + +void *jz4740_gpio_get_irq(void *gpio, unsigned pin); +bool jz4740_gpio_irq_set_mode(void *gpio_irq, unsigned mode); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/include/gpio-jz4780.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/include/gpio-jz4780.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,169 @@ +/* + * GPIO driver for Ingenic JZ4780. + * (See below for additional copyright and licensing notices.) + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Subject to other copyrights, being derived from the bcm2835.cc and + * omap.cc GPIO driver implementations. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#pragma once + +#include +#include +#include +#include "gpio.h" + + + +#ifdef __cplusplus + +#include + +// GPIO device control. + +class Gpio_jz4780_irq_pin : public Hw::Gpio_irq_pin +{ + unsigned _pin; + Hw::Register_block<32> _regs; + + // Convenience method for obtaining the bit corresponding to a pin. + + l4_uint32_t _pin_bit(unsigned pin) + { return 1 << (pin & 31); } + + void write_reg_pin(unsigned reg); + +public: + Gpio_jz4780_irq_pin(unsigned pin, Hw::Register_block<32> const ®s); + + void do_mask(); + void do_unmask(); + bool do_set_mode(unsigned mode); + int clear(); + bool enabled(); +}; + +class Gpio_jz4780_chip : public Hw::Gpio_chip +{ +private: + Hw::Register_block<32> _regs; + + l4_addr_t _start, _end; + unsigned _nr_pins; + l4_uint32_t _pull_ups, _pull_downs; + + // Convenience method for obtaining the bit corresponding to a pin. + + l4_uint32_t _pin_bit(unsigned pin) + { return 1 << (pin & 31); } + + // Convenience method for obtaining the bit position of a pin. + + unsigned _pin_shift(unsigned pin) + { return pin % 32; } + + // Permit only "aligned" accesses to registers. + + unsigned _reg_offset_check(unsigned pin_offset) const + { + switch (pin_offset) + { + case 0: + return 0; + + default: + throw -L4_EINVAL; + } + } + +public: + Gpio_jz4780_chip(l4_addr_t start, l4_addr_t end, + unsigned nr_pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs); + + // Obtain the number of pins. + + unsigned nr_pins() const { return _nr_pins; } + + // Unnecessary operations. + + void request(unsigned) {} + void free(unsigned) {} + + // Configuration methods. + + void setup(unsigned pin, unsigned mode, int value = 0); + void config_pull(unsigned pin, unsigned mode); + void config_pad(unsigned pin, unsigned func, unsigned value); + void config_get(unsigned pin, unsigned reg, unsigned *value); + + // Multiple pin configuration methods. + + void multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues = 0); + void multi_config_pad(Pin_slice const &mask, unsigned func, unsigned value = 0); + void multi_set(Pin_slice const &mask, unsigned data); + unsigned multi_get(unsigned offset); + + // IRQ pin configuration. + + Hw::Gpio_irq_pin *get_irq(unsigned pin); + + // Pin/port data methods. + + int get(unsigned pin); + void set(unsigned pin, int value); + +private: + void config(unsigned pin, unsigned mode); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4780_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs); + +void jz4780_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value); +void jz4780_gpio_config_pull(void *gpio, unsigned pin, unsigned mode); +void jz4780_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value); +void jz4780_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value); + +void jz4780_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues); +void jz4780_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value); +void jz4780_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data); +unsigned jz4780_gpio_multi_get(void *gpio, unsigned offset); + +int jz4780_gpio_get(void *gpio, unsigned pin); +void jz4780_gpio_set(void *gpio, unsigned pin, int value); + +void *jz4780_gpio_get_irq(void *gpio, unsigned pin); +bool jz4780_gpio_irq_set_mode(void *gpio_irq, unsigned mode); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/include/gpio.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/include/gpio.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,215 @@ +/* + * GPIO driver definitions. + * (See below for additional copyright and licensing notices.) + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Subject to other copyrights, being derived from the gpio headers in the io + * package. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#pragma once + +#include + +typedef struct Pin_slice +{ + unsigned offset; + unsigned mask; +} Pin_slice; + +#ifdef __cplusplus + +namespace Hw { + +// IRQ control for each GPIO pin. + +class Gpio_irq_pin +{ +public: + virtual void do_mask() = 0; + virtual void do_unmask() = 0; + virtual bool do_set_mode(unsigned mode) = 0; + virtual int clear() = 0; + virtual bool enabled() = 0; +}; + +// GPIO peripheral control. + +class Gpio_chip +{ +public: + /// Modes used for setup() + enum Fix_mode + { + Input = L4VBUS_GPIO_SETUP_INPUT, ///< Configure as input pin + Output = L4VBUS_GPIO_SETUP_OUTPUT, ///< Configure as output pin + Irq = L4VBUS_GPIO_SETUP_IRQ, ///< Configure as IRQ source + }; + + /// Modes used for pull up / pull down (config_pull()) + enum Pull_mode + { + Pull_none = L4VBUS_GPIO_PIN_PULL_NONE, ///< No pull up or pull down resistors + Pull_up = L4VBUS_GPIO_PIN_PULL_UP, ///< Enable pull up resistor + Pull_down = L4VBUS_GPIO_PIN_PULL_DOWN, ///< Enable pull down resistor + }; + + // Generic function options + enum Function_levels + { + Function_gpio, + Function_alt, + }; + + virtual void request(unsigned pin) = 0; + virtual void free(unsigned pin) = 0; + + /** + * \brief Request number of pins from GPIO chip + * \return Number of pins of this GPIO chip + */ + virtual unsigned nr_pins() const = 0; + + /** + * \brief Generic (platform independent) setup for a pin. + * \param pin the pin number to configure. + * \param mode the mode for the pin (see Fix_mode). + * \param value the value if the pin is configured as output. + */ + virtual void setup(unsigned pin, unsigned mode, int value = 0) = 0; + + /** + * \brief Generic (platform independet) function to set a pin's pull up/down mode + * \param pin The pin number to configure. + * \param mode The pull up/down mode (see Pull_mode). + */ + virtual void config_pull(unsigned pin, unsigned mode) = 0; + + /** + * \brief Set platform specific pad configuration. + * \param pin the pin to configure. + * \param func a platform specific sub-function of a pad to be configured + * \param value a platform specific value for the given sub-function. + */ + virtual void config_pad(unsigned pin, unsigned func, unsigned value) = 0; + + /** + * \brief Get Platform specific pad configuration. + * \param pin the pin to configure. + * \param func a platform specific sub-function of a pad to be configured + * \retparam value a platform specific value for the given sub-function. + */ + virtual void config_get(unsigned pin, unsigned func, unsigned *value) = 0; + + /** + * \brief Get the value of the given pin (generic API). + * \param pin the pin to read the value from. + */ + virtual int get(unsigned pin) = 0; + + /** + * \brief Set the value of the given pin (generic API). + * \pre The pin has to be configured as output before using this function, + * otherwise this call will be ignored. + * \param pin the pin to write the value to. + * \param value the value to program for output (0 or 1). + */ + virtual void set(unsigned pin, int value) = 0; + + /** + * \brief Setup multiple pins (generic API) + * \param mask the pins to actually set up. + * \param mode the mode for the pins (see Fix_mode). + * \param outvalue the value if configured as output. + */ + virtual void multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalue = 0) = 0; + + /** + * \brief Configure multiple pads at once (platform specific API). + * \param mask the pads to configure. + * \param func the platform-specific sub-function to configure. + * \param value the platform-specific value to set for the sub-function. + * \see config_pad() + */ + virtual void multi_config_pad(Pin_slice const &mask, unsigned func, unsigned value) = 0; + + /** + * \brief Set the value for multiple output pins at once. + * \param mask the pins that shall actually be set to the given values. + * \param data the bit-wise value for each pin to set (according to mask). + */ + virtual void multi_set(Pin_slice const &mask, unsigned data) = 0; + + /** + * \brief Get the value for all pins at once. + */ + virtual unsigned multi_get(unsigned offset) = 0; + + + void output(unsigned pin, int value) + { setup(pin, Output, value); } + + void input(unsigned pin) + { setup(pin, Input); } + + void multi_output(Pin_slice const &mask, unsigned data) + { multi_setup(mask, mask.mask, data); } + + void multi_input(Pin_slice const &mask) + { multi_setup(mask, ~mask.mask); } +}; + +} + +#else + +typedef enum { + false = 0, + true = 1 +} bool; + +/// Modes used for setup() +enum Fix_mode +{ + Fix_input = L4VBUS_GPIO_SETUP_INPUT, ///< Configure as input pin + Fix_output = L4VBUS_GPIO_SETUP_OUTPUT, ///< Configure as output pin + Fix_irq = L4VBUS_GPIO_SETUP_IRQ, ///< Configure as IRQ source +}; + +/// Modes used for pull up / pull down (config_pull()) +enum Pull_mode +{ + Pull_none = L4VBUS_GPIO_PIN_PULL_NONE, ///< No pull up or pull down resistors + Pull_up = L4VBUS_GPIO_PIN_PULL_UP, ///< Enable pull up resistor + Pull_down = L4VBUS_GPIO_PIN_PULL_DOWN, ///< Enable pull down resistor +}; + +// Generic function options +enum Function_levels +{ + Function_gpio, + Function_alt, +}; + +#endif /* __cplusplus */ diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libgpio.o.a +PC_FILENAME := libdrivers-gpio + +SRC_CC := jz4730.cc jz4740.cc jz4780.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/gpio/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/src/jz4730.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/src/jz4730.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,519 @@ +/* + * GPIO driver for Ingenic JZ4730. + * (See below for additional copyright and licensing notices.) + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Subject to other copyrights, being derived from the bcm2835.cc and + * omap.cc GPIO driver implementations. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#include +#include +#include + +#include "gpio-jz4730.h" + +// GPIO register offsets (x in A..D). + +enum Regs +{ + Port_data = 0x000, // PxGPDR + Port_direction = 0x004, // PxGPDIR + Pull_enable = 0x00c, // PxGPPUR + Port_function_lower = 0x010, // PxGPALR + Port_function_upper = 0x014, // PxGPAUR + Irq_detect_lower = 0x018, // PxGPDLR + Irq_detect_upper = 0x01c, // PxGPDUR + Irq_enable = 0x020, // PxGPIER + Irq_flag = 0x028, // PxGPFR +}; + + + +// Select the appropriate register and pin where two bits are assigned per pin, +// thus requiring two 32-bit registers to hold the configuration of 32 pins. + +static +uint32_t +_select_bank_for_pin(uint32_t reg_upper, uint32_t reg_lower, uint8_t pin, uint8_t *pin_out) +{ + if (pin < 16) + { + *pin_out = pin; + return reg_lower; + } + else + { + *pin_out = pin - 16; + return reg_upper; + } +} + + + +// IRQ control for each GPIO pin. + +Gpio_jz4730_irq_pin::Gpio_jz4730_irq_pin(unsigned pin, Hw::Register_block<32> const ®s) +: _pin(pin), _regs(regs) +{} + +void +Gpio_jz4730_irq_pin::write_reg_pin(unsigned reg) +{ + // Write the pin bit to the register, setting or clearing the pin + // depending on the register chosen. + + _regs[reg] = _pin_bit(_pin); +} + +void +Gpio_jz4730_irq_pin::clear_reg_pin(unsigned reg) +{ + // Clear the pin bit in the register. + + _regs[reg] = _regs[reg] & ~(_pin_bit(_pin)); +} + +void +Gpio_jz4730_irq_pin::set_reg_pin(unsigned reg) +{ + // Set the pin bit in the register. + + _regs[reg] = _regs[reg] | _pin_bit(_pin); +} + +// Clear the pin bits in the appropriate register. + +void +Gpio_jz4730_irq_pin::clear_reg_pins(uint32_t reg_upper, uint32_t reg_lower) +{ + uint8_t pin_out; + uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, _pin, &pin_out); + + _regs[reg] = _regs[reg] & ~(3 << (pin_out << 1)); +} + +// Clear and set the given value in the pin bits of the appropriate register. + +void +Gpio_jz4730_irq_pin::set_reg_pins(uint32_t reg_upper, uint32_t reg_lower, uint8_t value) +{ + uint8_t pin_out; + uint32_t reg = _select_bank_for_pin(reg_upper, reg_lower, _pin, &pin_out); + + _regs[reg] = (_regs[reg] & ~(3 << (pin_out << 1))) | (value << (pin_out << 1)); +} + +void Gpio_jz4730_irq_pin::do_mask() +{ + // Set the interrupt bit in the PxGPIER register. + + clear_reg_pin(Irq_enable); +} + +void Gpio_jz4730_irq_pin::do_unmask() +{ + // Set the interrupt bit in the PxGPIER register, first also clearing the + // flag bit in the PxGPFR register to allow interrupts to be delivered. + + clear_reg_pin(Irq_flag); + set_reg_pin(Irq_enable); +} + +bool Gpio_jz4730_irq_pin::do_set_mode(unsigned mode) +{ + // Standard comment found for this method: + // this operation touches multiple mmio registers and is thus + // not atomic, that's why we first mask the IRQ and if it was + // enabled we unmask it after we have changed the mode + + if (enabled()) + do_mask(); + + // Do the PxGPDUR/PxGPDLR configuration. + + switch(mode) + { + case L4_IRQ_F_LEVEL_HIGH: + set_reg_pins(Irq_detect_upper, Irq_detect_lower, 1); + break; + case L4_IRQ_F_LEVEL_LOW: + set_reg_pins(Irq_detect_upper, Irq_detect_lower, 0); + break; + case L4_IRQ_F_POS_EDGE: + set_reg_pins(Irq_detect_upper, Irq_detect_lower, 3); + break; + case L4_IRQ_F_NEG_EDGE: + set_reg_pins(Irq_detect_upper, Irq_detect_lower, 2); + break; + + default: + return false; + } + + // Do the PxGPDIR, PxGPAUR/PxGPALR configuration. + + clear_reg_pin(Port_direction); + clear_reg_pins(Port_function_upper, Port_function_lower); + + if (enabled()) + do_unmask(); + + return true; +} + +int Gpio_jz4730_irq_pin::clear() +{ + // Obtain the flag status for the pin, clearing it if set. + + l4_uint32_t e = _regs[Irq_flag] & (1UL << _pin); + if (e) + clear_reg_pin(Irq_flag); + + return (e >> _pin); +} + +bool Gpio_jz4730_irq_pin::enabled() +{ + return true; +} + + + +// Return two bitmaps for the given bitmap and value. + +static +void +_get_bitmaps(uint32_t bitmap, uint8_t value, uint32_t *upper, uint32_t *lower) +{ + uint32_t mask = 0x80000000; + + *upper = 0; *lower = 0; + + while (mask != 0x8000) + { + *upper = (*upper << 2) | (bitmap & mask ? value : 0); + mask >>= 1; + } + + while (mask != 0) + { + *lower = (*lower << 2) | (bitmap & mask ? value : 0); + mask >>= 1; + } +} + + + +// Initialise the GPIO controller. + +Gpio_jz4730_chip::Gpio_jz4730_chip(l4_addr_t start, l4_addr_t end, + unsigned nr_pins) +: _start(start), _end(end), + _nr_pins(nr_pins) +{ + _regs = new Hw::Mmio_register_block<32>(_start); +} + +// Return the value of a pin. + +int +Gpio_jz4730_chip::get(unsigned pin) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + l4_uint32_t val = _regs[Port_data]; + return (val >> _pin_shift(pin)) & 1; +} + +// Return multiple pin values. + +unsigned +Gpio_jz4730_chip::multi_get(unsigned offset) +{ + _reg_offset_check(offset); + return _regs[Port_data]; +} + +// Set the value of a pin. + +void +Gpio_jz4730_chip::set(unsigned pin, int value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + if (value) + _regs[Port_data] = _regs[Port_data] | _pin_bit(pin); + else + _regs[Port_data] = _regs[Port_data] & ~_pin_bit(pin); +} + +// Set multiple pin values. + +void +Gpio_jz4730_chip::multi_set(Pin_slice const &mask, unsigned data) +{ + _reg_offset_check(mask.offset); + _regs[Port_data] = (_regs[Port_data] & ~(mask.mask)) | data; +} + +// Set a pin up with the given mode and value (if appropriate). + +void +Gpio_jz4730_chip::setup(unsigned pin, unsigned mode, int value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + config(pin, mode); + + if (mode == Output) + set(pin, value); +} + +// Configuration of a pin using the generic input/output/IRQ mode. + +void +Gpio_jz4730_chip::config(unsigned pin, unsigned mode) +{ + _config(_pin_bit(pin), mode); +} + +void +Gpio_jz4730_chip::_config(unsigned bitmap, unsigned mode) +{ + uint32_t upper_mask, lower_mask; + unsigned bitmap_values = bitmap; + + switch (mode) + { + case Input: + case Irq: + // Clear the direction flags below. + bitmap_values = 0; + // Fall through to the next case to complete the operation. + + case Output: + // Clear the flags if set immediately above; otherwise, set them. + _regs[Port_direction] = (_regs[Port_direction] & ~bitmap) | bitmap_values; + + // Clear the port function for the bits. + _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask); + _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask); + _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask); + break; + + default: + break; + } +} + +// Pull-up configuration for a pin. + +void +Gpio_jz4730_chip::config_pull(unsigned pin, unsigned mode) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + _config_pull(_pin_bit(pin), mode); +} + +void +Gpio_jz4730_chip::_config_pull(unsigned bitmap, unsigned mode) +{ + switch (mode) + { + case Pull_none: + _regs[Pull_enable] = _regs[Pull_enable] & ~bitmap; + break; + case Pull_up: + _regs[Pull_enable] = _regs[Pull_enable] | bitmap; + break; + default: + // Invalid pull-up/down mode for pin. + throw -L4_EINVAL; + } +} + +// Pin function configuration. + +void +Gpio_jz4730_chip::config_pad(unsigned pin, unsigned func, unsigned value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + _config_pad(_pin_bit(pin), func, value); +} + +void +Gpio_jz4730_chip::_config_pad(unsigned bitmap, unsigned func, unsigned value) +{ + uint32_t upper_mask = 0, lower_mask = 0, upper = 0, lower = 0; + + if (value > 3) + throw -L4_EINVAL; + + switch (func) + { + case Hw::Gpio_chip::Function_alt: + _get_bitmaps(bitmap, value, &upper, &lower); + // Fall through to the next case to complete the operation. + + case Hw::Gpio_chip::Function_gpio: + _get_bitmaps(bitmap, 3, &upper_mask, &lower_mask); + _regs[Port_function_upper] = (_regs[Port_function_upper] & ~upper_mask) | upper; + _regs[Port_function_lower] = (_regs[Port_function_lower] & ~lower_mask) | lower; + break; + + default: + throw -L4_EINVAL; + } +} + +// Obtain a pin's configuration from a register in the supplied value. + +void +Gpio_jz4730_chip::config_get(unsigned pin, unsigned reg, unsigned *value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + *value = (_regs[reg] >> _pin_shift(pin)) & 1; +} + +// Obtain an IRQ abstraction for a pin. + +Hw::Gpio_irq_pin * +Gpio_jz4730_chip::get_irq(unsigned pin) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + return new Gpio_jz4730_irq_pin(pin, _regs); +} + +// Pull-up function configuration for multiple pins. + +void +Gpio_jz4730_chip::multi_config_pull(Pin_slice const &mask, unsigned mode) +{ + _config_pull(mask.mask << mask.offset, mode); +} + +// Pin function configuration for multiple pins. + +void +Gpio_jz4730_chip::multi_config_pad(Pin_slice const &mask, unsigned func, unsigned val) +{ + _config_pad(mask.mask << mask.offset, func, val); +} + +// Set up multiple pins with the given mode. + +void +Gpio_jz4730_chip::multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues) +{ + _config(mask.mask << mask.offset, mode); + + if (mode == Output) + multi_set(mask, outvalues); +} + + + +// C language interface functions. + +void *jz4730_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins) +{ + return (void *) new Gpio_jz4730_chip(start, end, pins); +} + +void jz4730_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) +{ + static_cast(gpio)->setup(pin, mode, value); +} + +void jz4730_gpio_config_pull(void *gpio, unsigned pin, unsigned mode) +{ + static_cast(gpio)->config_pull(pin, mode); +} + +void jz4730_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value) +{ + static_cast(gpio)->config_pad(pin, func, value); +} + +void jz4730_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value) +{ + static_cast(gpio)->config_get(pin, reg, value); +} + +void jz4730_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues) +{ + static_cast(gpio)->multi_setup(*mask, mode, outvalues); +} + +void jz4730_gpio_multi_config_pull(void *gpio, Pin_slice const *mask, unsigned mode) +{ + static_cast(gpio)->multi_config_pull(*mask, mode); +} + +void jz4730_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value) +{ + static_cast(gpio)->multi_config_pad(*mask, func, value); +} + +void jz4730_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data) +{ + static_cast(gpio)->multi_set(*mask, data); +} + +unsigned jz4730_gpio_multi_get(void *gpio, unsigned offset) +{ + return static_cast(gpio)->multi_get(offset); +} + +int jz4730_gpio_get(void *gpio, unsigned pin) +{ + return static_cast(gpio)->get(pin); +} + +void jz4730_gpio_set(void *gpio, unsigned pin, int value) +{ + static_cast(gpio)->set(pin, value); +} + +void *jz4730_gpio_get_irq(void *gpio, unsigned pin) +{ + return (void *) static_cast(gpio)->get_irq(pin); +} + +bool jz4730_gpio_irq_set_mode(void *gpio_irq, unsigned mode) +{ + return static_cast(gpio_irq)->do_set_mode(mode); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/src/jz4740.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/src/jz4740.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,452 @@ +/* + * GPIO driver for Ingenic JZ4740. + * (See below for additional copyright and licensing notices.) + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Subject to other copyrights, being derived from the bcm2835.cc and + * omap.cc GPIO driver implementations. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#include +#include +#include + +#include "gpio-jz4740.h" + +// GPIO register offsets (x in A..D). + +enum Regs +{ + Pin_level = 0x000, // PxPIN (read-only) + Port_data = 0x010, // PxDAT (read-only) + Port_data_set = 0x014, // PxDATS + Port_data_clear = 0x018, // PxDATC + Irq_mask = 0x020, // PxIM (read-only) + Irq_mask_set = 0x024, // PxIMS + Irq_mask_clear = 0x028, // PxIMC + Pull_disable = 0x030, // PxPE (read-only) + Pull_disable_set = 0x034, // PxPES + Pull_disable_clear = 0x038, // PxPEC + Port_function = 0x040, // PxFUN (read-only) + Port_function_set = 0x044, // PxFUNS + Port_function_clear = 0x048, // PxFUNC + Port_select = 0x050, // PxSEL (read-only) + Port_select_set = 0x054, // PxSELS + Port_select_clear = 0x058, // PxSELC + Port_dir = 0x060, // PxDIR (read-only) + Port_dir_set = 0x064, // PxDIRS + Port_dir_clear = 0x068, // PxDIRC + Port_trigger = 0x070, // PxTRG (read-only) + Port_trigger_set = 0x074, // PxTRGS + Port_trigger_clear = 0x078, // PxTRGC + Irq_flag = 0x080, // PxFLG (read-only) + Irq_flag_clear = 0x084, // PxFLGC +}; + + + +// IRQ control for each GPIO pin. + +Gpio_jz4740_irq_pin::Gpio_jz4740_irq_pin(unsigned pin, Hw::Register_block<32> const ®s) +: _pin(pin), _regs(regs) +{} + +void +Gpio_jz4740_irq_pin::write_reg_pin(unsigned reg) +{ + // Write the pin bit to the register, setting or clearing the pin + // depending on the register chosen. + + _regs[reg] = _pin_bit(_pin); +} + +void Gpio_jz4740_irq_pin::do_mask() +{ + // Set the interrupt bit in the PxIM register. + + write_reg_pin(Irq_mask_set); +} + +void Gpio_jz4740_irq_pin::do_unmask() +{ + // Clear the interrupt bit in the PxIM register, first also clearing the + // flag bit in the PxFLG register to allow interrupts to be delivered. + + write_reg_pin(Irq_flag_clear); + write_reg_pin(Irq_mask_clear); +} + +bool Gpio_jz4740_irq_pin::do_set_mode(unsigned mode) +{ + // Standard comment found for this method: + // this operation touches multiple mmio registers and is thus + // not atomic, that's why we first mask the IRQ and if it was + // enabled we unmask it after we have changed the mode + + if (enabled()) + do_mask(); + + // Do the PxTRG, PxFUN, PxSEL and PxDIR configuration. + + switch(mode) + { + case L4_IRQ_F_LEVEL_HIGH: + write_reg_pin(Port_trigger_clear); + write_reg_pin(Port_function_clear); + write_reg_pin(Port_select_set); + write_reg_pin(Port_dir_set); + break; + case L4_IRQ_F_LEVEL_LOW: + write_reg_pin(Port_trigger_clear); + write_reg_pin(Port_function_clear); + write_reg_pin(Port_select_set); + write_reg_pin(Port_dir_clear); + break; + case L4_IRQ_F_POS_EDGE: + write_reg_pin(Port_trigger_set); + write_reg_pin(Port_function_clear); + write_reg_pin(Port_select_set); + write_reg_pin(Port_dir_set); + break; + case L4_IRQ_F_NEG_EDGE: + write_reg_pin(Port_trigger_set); + write_reg_pin(Port_function_clear); + write_reg_pin(Port_select_set); + write_reg_pin(Port_dir_clear); + break; + + default: + return false; + } + + if (enabled()) + do_unmask(); + + return true; +} + +int Gpio_jz4740_irq_pin::clear() +{ + // Obtain the flag status for the pin, clearing it if set. + + l4_uint32_t e = _regs[Irq_flag] & (1UL << _pin); + if (e) + _regs[Irq_flag_clear] = e; + + return (e >> _pin); +} + +bool Gpio_jz4740_irq_pin::enabled() +{ + return true; +} + + + +// Initialise the GPIO controller. + +Gpio_jz4740_chip::Gpio_jz4740_chip(l4_addr_t start, l4_addr_t end, + unsigned nr_pins) +: _start(start), _end(end), + _nr_pins(nr_pins) +{ + _regs = new Hw::Mmio_register_block<32>(_start); +} + +// Return the value of a pin. + +int +Gpio_jz4740_chip::get(unsigned pin) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + l4_uint32_t val = _regs[Pin_level]; + return (val >> _pin_shift(pin)) & 1; +} + +// Return multiple pin values. + +unsigned +Gpio_jz4740_chip::multi_get(unsigned offset) +{ + _reg_offset_check(offset); + return _regs[Pin_level]; +} + +// Set the value of a pin. + +void +Gpio_jz4740_chip::set(unsigned pin, int value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + l4_uint32_t reg_set = value ? Port_data_set : Port_data_clear; + _regs[reg_set] = _pin_bit(pin); +} + +// Set multiple pin values. + +void +Gpio_jz4740_chip::multi_set(Pin_slice const &mask, unsigned data) +{ + _reg_offset_check(mask.offset); + if (mask.mask & data) + _regs[Port_data_set] = (mask.mask & data); + if (mask.mask & ~data) + _regs[Port_data_clear] = (mask.mask & ~data); +} + +// Set a pin up with the given mode and value (if appropriate). + +void +Gpio_jz4740_chip::setup(unsigned pin, unsigned mode, int value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + config(pin, mode); + + if (mode == Output) + set(pin, value); +} + +// Configuration of a pin using the generic input/output/IRQ mode. + +void +Gpio_jz4740_chip::config(unsigned pin, unsigned mode) +{ + _config(_pin_bit(pin), mode); +} + +void +Gpio_jz4740_chip::_config(unsigned bitmap, unsigned mode) +{ + switch (mode) + { + case Input: + _regs[Port_function_clear] = bitmap; + _regs[Port_select_clear] = bitmap; + _regs[Port_dir_clear] = bitmap; + break; + case Output: + _regs[Port_function_clear] = bitmap; + _regs[Port_select_clear] = bitmap; + _regs[Port_dir_set] = bitmap; + break; + case Irq: + _regs[Port_function_clear] = bitmap; + _regs[Port_select_set] = bitmap; + // The direction depends on the actual trigger mode. + break; + default: + break; + } +} + +// Pull-up configuration for a pin. + +void +Gpio_jz4740_chip::config_pull(unsigned pin, unsigned mode) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + _config_pull(_pin_bit(pin), mode); +} + +void +Gpio_jz4740_chip::_config_pull(unsigned bitmap, unsigned mode) +{ + switch (mode) + { + case Pull_none: + _regs[Pull_disable_set] = bitmap; + break; + case Pull_up: + _regs[Pull_disable_clear] = bitmap; + break; + default: + // Invalid pull-up/down mode for pin. + throw -L4_EINVAL; + } +} + +// Pin function configuration. + +void +Gpio_jz4740_chip::config_pad(unsigned pin, unsigned func, unsigned value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + _config_pad(_pin_bit(pin), func, value); +} + +void +Gpio_jz4740_chip::_config_pad(unsigned bitmap, unsigned func, unsigned value) +{ + if (value > 1) + throw -L4_EINVAL; + + switch (func) + { + case Hw::Gpio_chip::Function_gpio: + _regs[Port_function_clear] = bitmap; + break; + + // Support two different device functions. + + case Hw::Gpio_chip::Function_alt: + _regs[Port_function_set] = bitmap; + _regs[value ? Port_select_set : Port_select_clear] = bitmap; + break; + default: + throw -L4_EINVAL; + } +} + +// Obtain a pin's configuration from a register in the supplied value. + +void +Gpio_jz4740_chip::config_get(unsigned pin, unsigned reg, unsigned *value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + *value = (_regs[reg] >> _pin_shift(pin)) & 1; +} + +// Obtain an IRQ abstraction for a pin. + +Hw::Gpio_irq_pin * +Gpio_jz4740_chip::get_irq(unsigned pin) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + return new Gpio_jz4740_irq_pin(pin, _regs); +} + +// Pull-up function configuration for multiple pins. + +void +Gpio_jz4740_chip::multi_config_pull(Pin_slice const &mask, unsigned mode) +{ + _config_pull(mask.mask << mask.offset, mode); +} + +// Pin function configuration for multiple pins. + +void +Gpio_jz4740_chip::multi_config_pad(Pin_slice const &mask, unsigned func, unsigned val) +{ + _config_pad(mask.mask << mask.offset, func, val); +} + +// Set up multiple pins with the given mode. + +void +Gpio_jz4740_chip::multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues) +{ + _config(mask.mask << mask.offset, mode); + + if (mode == Output) + multi_set(mask, outvalues); +} + + + +// C language interface functions. + +void *jz4740_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins) +{ + return (void *) new Gpio_jz4740_chip(start, end, pins); +} + +void jz4740_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) +{ + static_cast(gpio)->setup(pin, mode, value); +} + +void jz4740_gpio_config_pull(void *gpio, unsigned pin, unsigned mode) +{ + static_cast(gpio)->config_pull(pin, mode); +} + +void jz4740_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value) +{ + static_cast(gpio)->config_pad(pin, func, value); +} + +void jz4740_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value) +{ + static_cast(gpio)->config_get(pin, reg, value); +} + +void jz4740_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues) +{ + static_cast(gpio)->multi_setup(*mask, mode, outvalues); +} + +void jz4740_gpio_multi_config_pull(void *gpio, Pin_slice const *mask, unsigned mode) +{ + static_cast(gpio)->multi_config_pull(*mask, mode); +} + +void jz4740_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value) +{ + static_cast(gpio)->multi_config_pad(*mask, func, value); +} + +void jz4740_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data) +{ + static_cast(gpio)->multi_set(*mask, data); +} + +unsigned jz4740_gpio_multi_get(void *gpio, unsigned offset) +{ + return static_cast(gpio)->multi_get(offset); +} + +int jz4740_gpio_get(void *gpio, unsigned pin) +{ + return static_cast(gpio)->get(pin); +} + +void jz4740_gpio_set(void *gpio, unsigned pin, int value) +{ + static_cast(gpio)->set(pin, value); +} + +void *jz4740_gpio_get_irq(void *gpio, unsigned pin) +{ + return (void *) static_cast(gpio)->get_irq(pin); +} + +bool jz4740_gpio_irq_set_mode(void *gpio_irq, unsigned mode) +{ + return static_cast(gpio_irq)->do_set_mode(mode); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/gpio/src/jz4780.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/gpio/src/jz4780.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,458 @@ +/* + * GPIO driver for Ingenic JZ4780. + * (See below for additional copyright and licensing notices.) + * + * (c) 2017 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Subject to other copyrights, being derived from the bcm2835.cc and + * omap.cc GPIO driver implementations. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#include +#include +#include + +#include "gpio-jz4780.h" + +/* +GPIO register offsets (x in A..F). + +Register summary: + +PxINT 0 (function/GPIO) 1 (interrupt) +PxMSK 0 (function) 1 (GPIO) 0 (IRQ enable)/1 (IRQ disable) +PxPAT1 0 (function 0/1) 1 (function 2/3) 0 (output) 1 (input) 0 (level trigger) 1 (edge trigger) +PxPAT0 0 (function 0) 0 (function 2) 0 (output value 0) 0 (low level) 0 (falling edge) + 1 (function 1) 1 (function 3) 1 (output value 1) 1 (high level) 1 (rising edge) +*/ + +enum Regs +{ + Pin_level = 0x000, // PxPIN (read-only) + + Port_int = 0x010, // PxINT + Port_int_set = 0x014, // PxINTS + Port_int_clear = 0x018, // PxINTC + + Irq_mask = 0x020, // PxMSK (for PxINT == 1) + Irq_mask_set = 0x024, // PxMSKS + Irq_mask_clear = 0x028, // PxMSKC + Port_gpio = 0x020, // PxMSK (for PxINT == 0) + Port_gpio_set = 0x024, // PxMSKS + Port_gpio_clear = 0x028, // PxMSKC + + Port_trigger = 0x030, // PxPAT1 (for PxINT == 1) + Port_trigger_set = 0x034, // PxPAT1S + Port_trigger_clear = 0x038, // PxPAT1C + Port_dir = 0x030, // PxPAT1 (for PxINT == 0, PxMSK == 1) + Port_dir_set = 0x034, // PxPAT1S + Port_dir_clear = 0x038, // PxPAT1C + Port_group1 = 0x030, // PxPAT1 (for PxINT == 0, PxMSK == 0) + Port_group1_set = 0x034, // PxPAT1S + Port_group1_clear = 0x038, // PxPAT1C + + Port_level = 0x040, // PxPAT0 (for PxINT == 1) + Port_level_set = 0x044, // PxPAT0S + Port_level_clear = 0x048, // PxPAT0C + Port_data = 0x040, // PxPAT0 (for PxINT == 0, PxMSK == 1, PxPAT1 == 0) + Port_data_set = 0x044, // PxPAT0S + Port_data_clear = 0x048, // PxPAT0C + Port_group0 = 0x040, // PxPAT0 (for PxINT == 0, PxMSK == 0) + Port_group0_set = 0x044, // PxPAT0S + Port_group0_clear = 0x048, // PxPAT0C + + Irq_flag = 0x050, // PxFLG (read-only) + Irq_flag_clear = 0x058, // PxFLGC + + Pull_disable = 0x070, // PxPE + Pull_disable_set = 0x074, // PxPES + Pull_disable_clear = 0x078, // PxPEC +}; + + + +// IRQ control for each GPIO pin. + +Gpio_jz4780_irq_pin::Gpio_jz4780_irq_pin(unsigned pin, Hw::Register_block<32> const ®s) +: _pin(pin), _regs(regs) +{} + +void +Gpio_jz4780_irq_pin::write_reg_pin(unsigned reg) +{ + // Write the pin bit to the register, setting or clearing the pin + // depending on the register chosen. + + _regs[reg] = _pin_bit(_pin); +} + +void Gpio_jz4780_irq_pin::do_mask() +{ + // Set the interrupt bit in the PxIM register. + + write_reg_pin(Irq_mask_set); +} + +void Gpio_jz4780_irq_pin::do_unmask() +{ + // Clear the interrupt bit in the PxIM register, first also clearing the + // flag bit in the PxFLG register to allow interrupts to be delivered. + + write_reg_pin(Irq_flag_clear); + write_reg_pin(Irq_mask_clear); +} + +bool Gpio_jz4780_irq_pin::do_set_mode(unsigned mode) +{ + // Standard comment found for this method: + // this operation touches multiple mmio registers and is thus + // not atomic, that's why we first mask the IRQ and if it was + // enabled we unmask it after we have changed the mode + + if (enabled()) + do_mask(); + + // Do the PxINT, PxPAT1 and PxPAT0 configuration. + + switch(mode) + { + case L4_IRQ_F_LEVEL_HIGH: + write_reg_pin(Port_int_set); + write_reg_pin(Port_trigger_clear); + write_reg_pin(Port_level_set); + break; + case L4_IRQ_F_LEVEL_LOW: + write_reg_pin(Port_int_set); + write_reg_pin(Port_trigger_clear); + write_reg_pin(Port_level_clear); + break; + case L4_IRQ_F_POS_EDGE: + write_reg_pin(Port_int_set); + write_reg_pin(Port_trigger_set); + write_reg_pin(Port_level_set); + break; + case L4_IRQ_F_NEG_EDGE: + write_reg_pin(Port_int_set); + write_reg_pin(Port_trigger_set); + write_reg_pin(Port_level_clear); + break; + + default: + return false; + } + + if (enabled()) + do_unmask(); + + return true; +} + +int Gpio_jz4780_irq_pin::clear() +{ + // Obtain the flag status for the pin, clearing it if set. + + l4_uint32_t e = _regs[Irq_flag] & (1UL << _pin); + if (e) + _regs[Irq_flag_clear] = e; + + return (e >> _pin); +} + +bool Gpio_jz4780_irq_pin::enabled() +{ + return true; +} + + + +// Initialise the GPIO controller. + +Gpio_jz4780_chip::Gpio_jz4780_chip(l4_addr_t start, l4_addr_t end, + unsigned nr_pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs) +: _start(start), _end(end), + _nr_pins(nr_pins), + _pull_ups(pull_ups), _pull_downs(pull_downs) +{ + _regs = new Hw::Mmio_register_block<32>(_start); +} + +// Return the value of a pin. + +int +Gpio_jz4780_chip::get(unsigned pin) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + l4_uint32_t val = _regs[Pin_level]; + return (val >> _pin_shift(pin)) & 1; +} + +// Return multiple pin values. + +unsigned +Gpio_jz4780_chip::multi_get(unsigned offset) +{ + _reg_offset_check(offset); + return _regs[Pin_level]; +} + +// Set the value of a pin. + +void +Gpio_jz4780_chip::set(unsigned pin, int value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + l4_uint32_t reg_set = value ? Port_data_set : Port_data_clear; + _regs[reg_set] = _pin_bit(pin); +} + +// Set multiple pin values. + +void +Gpio_jz4780_chip::multi_set(Pin_slice const &mask, unsigned data) +{ + _reg_offset_check(mask.offset); + if (mask.mask & data) + _regs[Port_data_set] = (mask.mask & data); + if (mask.mask & ~data) + _regs[Port_data_clear] = (mask.mask & ~data); +} + +// Set a pin up with the given mode and value (if appropriate). + +void +Gpio_jz4780_chip::setup(unsigned pin, unsigned mode, int value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + config(pin, mode); + + if (mode == Output) + set(pin, value); +} + +// Configuration of a pin using the generic input/output/IRQ mode. + +void +Gpio_jz4780_chip::config(unsigned pin, unsigned mode) +{ + switch (mode) + { + case Input: + _regs[Port_int_clear] = _pin_bit(pin); + _regs[Port_gpio_set] = _pin_bit(pin); + _regs[Port_dir_set] = _pin_bit(pin); + break; + case Output: + _regs[Port_int_clear] = _pin_bit(pin); + _regs[Port_gpio_set] = _pin_bit(pin); + _regs[Port_dir_clear] = _pin_bit(pin); + break; + case Irq: + _regs[Port_int_set] = _pin_bit(pin); + // Other details depend on the actual trigger mode. + break; + default: + break; + } +} + +// Pull-up/down configuration for a pin. + +void +Gpio_jz4780_chip::config_pull(unsigned pin, unsigned mode) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + switch (mode) + { + case Pull_none: + _regs[Pull_disable_set] = _pin_bit(pin); + break; + case Pull_down: + if (_pin_bit(pin) & _pull_downs) + _regs[Pull_disable_clear] = _pin_bit(pin); + break; + case Pull_up: + if (_pin_bit(pin) & _pull_ups) + _regs[Pull_disable_clear] = _pin_bit(pin); + break; + default: + // Invalid pull-up/down mode for pin. + throw -L4_EINVAL; + } +} + +// Pin function configuration. + +void +Gpio_jz4780_chip::config_pad(unsigned pin, unsigned func, unsigned value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + if (value > 1) + throw -L4_EINVAL; + + switch (func) + { + // Support two different outputs. + + case Hw::Gpio_chip::Function_gpio: + _regs[Port_int_clear] = _pin_bit(pin); + _regs[Port_gpio_set] = _pin_bit(pin); + _regs[value & 1 ? Port_data_set : Port_data_clear] = _pin_bit(pin); + break; + + // Support four different device functions. + + case Hw::Gpio_chip::Function_alt: + _regs[Port_int_clear] = _pin_bit(pin); + _regs[Port_gpio_clear] = _pin_bit(pin); + _regs[value & 2 ? Port_group1_set : Port_group1_clear] = _pin_bit(pin); + _regs[value & 1 ? Port_group0_set : Port_group0_clear] = _pin_bit(pin); + break; + default: + throw -L4_EINVAL; + } +} + +// Obtain a pin's configuration from a register in the supplied value. + +void +Gpio_jz4780_chip::config_get(unsigned pin, unsigned reg, unsigned *value) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + *value = (_regs[reg] >> _pin_shift(pin)) & 1; +} + +// Obtain an IRQ abstraction for a pin. + +Hw::Gpio_irq_pin * +Gpio_jz4780_chip::get_irq(unsigned pin) +{ + if (pin >= _nr_pins) + throw -L4_EINVAL; + + return new Gpio_jz4780_irq_pin(pin, _regs); +} + +// Pin function configuration for multiple pins. + +void +Gpio_jz4780_chip::multi_config_pad(Pin_slice const &mask, unsigned func, unsigned val) +{ + unsigned m = mask.mask; + for (unsigned pin = mask.offset; pin < _nr_pins; ++pin, m >>= 1) + if (m & 1) + config_pad(pin, func, val); +} + +// Set up multiple pins with the given mode. + +void +Gpio_jz4780_chip::multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues) +{ + unsigned m = mask.mask; + for (unsigned pin = mask.offset; pin < _nr_pins; ++pin, m >>= 1, outvalues >>= 1) + if (m & 1) + setup(pin, mode, outvalues & 1); +} + + + +// C language interface functions. + +void *jz4780_gpio_init(l4_addr_t start, l4_addr_t end, unsigned pins, + l4_uint32_t pull_ups, l4_uint32_t pull_downs) +{ + return (void *) new Gpio_jz4780_chip(start, end, pins, pull_ups, pull_downs); +} + +void jz4780_gpio_setup(void *gpio, unsigned pin, unsigned mode, int value) +{ + static_cast(gpio)->setup(pin, mode, value); +} + +void jz4780_gpio_config_pull(void *gpio, unsigned pin, unsigned mode) +{ + static_cast(gpio)->config_pull(pin, mode); +} + +void jz4780_gpio_config_pad(void *gpio, unsigned pin, unsigned func, unsigned value) +{ + static_cast(gpio)->config_pad(pin, func, value); +} + +void jz4780_gpio_config_get(void *gpio, unsigned pin, unsigned reg, unsigned *value) +{ + static_cast(gpio)->config_get(pin, reg, value); +} + +void jz4780_gpio_multi_setup(void *gpio, Pin_slice const *mask, unsigned mode, unsigned outvalues) +{ + static_cast(gpio)->multi_setup(*mask, mode, outvalues); +} + +void jz4780_gpio_multi_config_pad(void *gpio, Pin_slice const *mask, unsigned func, unsigned value) +{ + static_cast(gpio)->multi_config_pad(*mask, func, value); +} + +void jz4780_gpio_multi_set(void *gpio, Pin_slice const *mask, unsigned data) +{ + static_cast(gpio)->multi_set(*mask, data); +} + +unsigned jz4780_gpio_multi_get(void *gpio, unsigned offset) +{ + return static_cast(gpio)->multi_get(offset); +} + +int jz4780_gpio_get(void *gpio, unsigned pin) +{ + return static_cast(gpio)->get(pin); +} + +void jz4780_gpio_set(void *gpio, unsigned pin, int value) +{ + static_cast(gpio)->set(pin, value); +} + +void *jz4780_gpio_get_irq(void *gpio, unsigned pin) +{ + return (void *) static_cast(gpio)->get_irq(pin); +} + +bool jz4780_gpio_irq_set_mode(void *gpio_irq, unsigned mode) +{ + return static_cast(gpio_irq)->do_set_mode(mode); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/i2c/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/i2c/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/i2c/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/i2c/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/i2c/include/i2c-jz4780.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/i2c/include/i2c-jz4780.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,116 @@ +/* + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +#ifdef __cplusplus + +#include +#include + +// I2C channel. + +class I2c_jz4780_channel +{ +private: + Hw::Register_block<32> _regs; + Cpm_jz4780_chip *_cpm; + uint32_t _frequency; + unsigned queued, _pos, _reqpos, _total; + uint8_t *_buf; + int _fail, _stop, _last; + +public: + I2c_jz4780_channel(l4_addr_t start, Cpm_jz4780_chip *cpm, + uint32_t frequency); + + void set_target(uint8_t addr); + void start_read(uint8_t buf[], unsigned total); + void read(); + int read_done(); + unsigned have_read(); + int read_incomplete(); + void write(uint8_t buf[], unsigned total); + void stop(); + +private: + void disable(); + void enable(); + + int active(); + int have_input(); + int have_output(); + int can_send(); + int read_failed(); + int write_failed(); + + void reset_flags(); + void init_parameters(); + void set_frequency(); + + void set_read_threshold(); + void queue_reads(); + void queue_writes(uint8_t buf[], unsigned *pos, unsigned total); + void store_reads(); +}; + +// I2C device control. + +class I2c_jz4780_chip +{ +private: + l4_addr_t _start, _end; + Cpm_jz4780_chip *_cpm; + uint32_t _frequency; + +public: + I2c_jz4780_chip(l4_addr_t start, l4_addr_t end, Cpm_jz4780_chip *cpm, + uint32_t frequency); + + I2c_jz4780_channel *get_channel(uint8_t channel); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4780_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm, + uint32_t frequency); + +void *jz4780_i2c_get_channel(void *i2c, uint8_t channel); + +void jz4780_i2c_set_target(void *i2c_channel, uint8_t addr); +void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned total); +void jz4780_i2c_read(void *i2c_channel); +int jz4780_i2c_read_done(void *i2c_channel); +unsigned jz4780_i2c_have_read(void *i2c_channel); +int jz4780_i2c_read_incomplete(void *i2c_channel); +void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned total); +void jz4780_i2c_stop(void *i2c_channel); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/i2c/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/i2c/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libi2c.o.a +PC_FILENAME := libdrivers-i2c + +SRC_CC := jz4780.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/i2c/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/i2c/src/jz4780.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/i2c/src/jz4780.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,693 @@ +/* + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include +#include + +#include + +/* +I2C pins: + +I2C0: PD30/SMB0_SDA, PD31/SMB0_SCK +I2C1: PD30/SMB1_SDA, PD31/SMB1_SCK (pulled up on CI20) +I2C2: PF16/SMB2_SDA, PF17/SMB2_SCK + PWM: PD10/SMB3_SDA, PD11/SMB3_SCK + PWM: PE3/SMB4_SDA, PE4/SMB4_SCK +I2C4: PE12/SMB4_SDA, PE13/SMB4_SCK +HDMI: PF25/SMB4_SDA/DDCSDA, PF24/SMB4_SCK/DDCSCK + +See: http://mipscreator.imgtec.com/CI20/hardware/board/ci20_jz4780_v2.0.pdf +*/ + +enum Regs +{ + Smb_control = 0x000, // SMBCON + Smb_target_address = 0x004, // SMBTAR + Smb_slave_address = 0x008, // SMBSAR + Smb_data_command = 0x010, // SMBDC + Std_high_count = 0x014, // SMBSHCNT + Std_low_count = 0x018, // SMBSLCNT + Fast_high_count = 0x01c, // SMBFHCNT + Fast_low_count = 0x020, // SMBFLCNT + Int_status = 0x02c, // SMBINTST (read-only) + Int_mask = 0x030, // SMBINTM + + Rx_fifo_thold = 0x038, // SMBRXTL + Tx_fifo_thold = 0x03c, // SMBTXTL + Int_combined_clear = 0x040, // SMBCINT (read-only) + Int_rx_uf_clear = 0x044, // SMBCRXUF (read-only) + Int_rx_of_clear = 0x048, // SMBCRXOF (read-only) + Int_tx_of_clear = 0x04c, // SMBCTXOF (read-only) + Int_rd_req_clear = 0x050, // SMBCRXREQ (read-only) + Int_tx_abort_clear = 0x054, // SMBCTXABT (read-only) + Int_rx_done_clear = 0x058, // SMBCRXDN (read-only) + Int_activity_clear = 0x05c, // SMBCACT (read-only) + Int_stop_clear = 0x060, // SMBCSTP (read-only) + Int_start_clear = 0x064, // SMBCSTT (read-only) + Int_call_clear = 0x068, // SMBCGC (read-only) + Smb_enable = 0x06c, // SMBENB + Smb_status = 0x070, // SMBST (read-only) + + Tx_fifo_count = 0x074, // SMBTXFLR (read-only) + Rx_fifo_count = 0x078, // SMBRXFLR (read-only) + + Trans_abort_status0 = 0x080, // SMBABTSRC (read-only) + Trans_abort_status1 = 0x084, // ... (read-only) + + Smb_dma_ctrl = 0x088, // SMBDMACR + Smb_trans_data_lvl = 0x08c, // SMBDMATDLR + Smb_recv_data_lvl = 0x090, // SMBDMARDLR + Smb_sda_setup_time = 0x094, // SMBSDASU + Smb_ack_call = 0x098, // SMBACKGC + + Smb_enable_status = 0x09c, // SMBENBST (read-only) + Smb_sda_hold_time = 0x0d0, // SMBSDAHD + + Smb_block_offset = 0x1000 +}; + +enum Smb_control_bits : unsigned +{ + Smb_no_stop_empty = 0x80, // STPHLD (no STP condition when queue empty) + Smb_disable_slave = 0x40, // SLVDIS (slave disabled) + Smb_enable_restart = 0x20, // REST + Smb_enable_master = 0x01, // MD (master enabled) + Smb_speed_bit = 1, // SPD +}; + +enum Smb_enable_bits : unsigned +{ + Smb_enable_enabled = 0x01, // SMBEN +}; + +enum Smb_status_bits : unsigned +{ + Smb_status_master_act = 0x20, // MSTACT (master active) + Smb_status_rx_nempty = 0x08, // RFNE (read queue not empty) + Smb_status_tx_empty = 0x04, // TFE (write queue empty) + Smb_status_tx_nfull = 0x02, // TFNF (write queue not full) + Smb_status_active = 0x01, // ACT (device active as master or slave) +}; + +enum Smb_target_bits : unsigned +{ + Smb_target_7bits = 0x7f, +}; + +enum Smb_hold_control_bits : unsigned +{ + Smb_hold_enable = 0x100, // HDENB + Smb_hold_disable = 0x000, // HDENB + Smb_hold_mask = 0x1ff, +}; + +enum Smb_setup_control_bits : unsigned +{ + Smb_setup_mask = 0x0ff, +}; + +enum Smb_command_bits : unsigned +{ + Smb_command_read = 0x100, // CMD + Smb_command_write = 0x000, // CMD +}; + +enum Smb_fifo_bits : unsigned +{ + Smb_fifo_limit = 16, +}; + +enum Int_bits : unsigned +{ + Int_call = 0x800, // IGC (general call received) + Int_start = 0x400, // ISTT (start/restart condition occurred) + Int_stop = 0x200, // ISTP (stop condition occurred) + Int_activity = 0x100, // IACT (bus activity interrupt) + Int_rx_done = 0x080, // RXDN (read from master device done) + Int_tx_abort = 0x040, // TXABT (transmit abort) + Int_rd_req = 0x020, // RDREQ (read request from master device) + Int_tx_empty = 0x010, // TXEMP (threshold reached or passed) + Int_tx_of = 0x008, // TXOF (overflow when writing to queue) + Int_rx_full = 0x004, // RXFL (threshold reached or exceeded) + Int_rx_of = 0x002, // RXOF (overflow from device) + Int_rx_uf = 0x001, // RXUF (underflow when reading from queue) +}; + + + +// Initialise a channel. + +I2c_jz4780_channel::I2c_jz4780_channel(l4_addr_t start, + Cpm_jz4780_chip *cpm, + uint32_t frequency) +: _cpm(cpm), _frequency(frequency) +{ + _regs = new Hw::Mmio_register_block<32>(start); +} + +// Enable the channel. + +void +I2c_jz4780_channel::enable() +{ + _regs[Smb_control] = _regs[Smb_control] | Smb_no_stop_empty; + + _regs[Smb_enable] = Smb_enable_enabled; + while (!(_regs[Smb_enable_status] & Smb_enable_enabled)); +} + +// Disable the channel. + +void +I2c_jz4780_channel::disable() +{ + _regs[Smb_enable] = 0; + while (_regs[Smb_enable_status] & Smb_enable_enabled); +} + +// Set the frequency-related peripheral parameters. + +void +I2c_jz4780_channel::set_frequency() +{ + // The APB clock (PCLK) is used to drive I2C transfers. Its value must be + // obtained from the CPM unit. It is known as SMB_CLK here and is scaled to + // kHz in order to keep the numbers easily representable, as is the bus + // frequency. + + uint32_t smb_clk = _cpm->get_pclock_frequency() / 1000; + uint32_t i2c_clk = _frequency / 1000; + unsigned speed = (i2c_clk <= 100) ? 1 : 2; + + _regs[Smb_control] = _regs[Smb_control] | (speed << Smb_speed_bit) | + Smb_disable_slave | + Smb_enable_restart | + Smb_enable_master; + + // According to the programming manual, if the PCLK period is T{SMB_CLK} + // then the I2C clock period is... + + // T{SCL} = T{SCL_high} + T{SCL_low} + + // Where... + + // T{SCL_low} = T{SMB_CLK} * (#cycles for low signal) + // T{SCL_high} = T{SMB_CLK} * (#cycles for high signal) + + // Since, with minimum periods being defined... + + // T{SCL} >= T{min_SCL} + // T{SCL_low} >= T{min_SCL_low} + // T{SCL_high} >= T{min_SCL_high} + // T{min_SCL} = T{min_SCL_low} + T{min_SCL_high} + + // Then the following applies... + + // T{SMB_CLK} * (#cycles for low signal)) >= T{min_SCL_low} + // T{SMB_CLK} * (#cycles for high signal) >= T{min_SCL_high} + + // To work with different clock speeds while maintaining the low-to-high + // ratios: + + // T{min_SCL_low} = T{min_SCL} * T{min_SCL_low} / T{min_SCL} + // = T{min_SCL} * (T{min_SCL_low} / (T{min_SCL_low} + T{min_SCL_high})) + + // T{min_SCL_high} = T{min_SCL} * T{min_SCL_high} / T{min_SCL} + // = T{min_SCL} * (T{min_SCL_high} / (T{min_SCL_low} + T{min_SCL_high})) + + // Constraints are given with respect to the high and low count registers. + + // #cycles for high signal = SMBxHCNT + 8 + // #cycles for low signal = SMBxLCNT + 1 + + // From earlier, this yields... + + // T{SMB_CLK} * (SMBxLCNT + 1) >= T{min_SCL_low} + // T{SMB_CLK} * (SMBxHCNT + 8) >= T{min_SCL_high} + + // Rearranging... + + // SMBxLCNT >= (T{min_SCL_low} / T{SMB_CLK}) - 1 + // >= T{min_SCL_low} * SMB_CLK - 1 + + // SMBxHCNT >= (T{min_SCL_high} / T{SMB_CLK}) - 8 + // >= T{min_SCL_high} * SMB_CLK - 8 + + // Introducing the definitions for the high and low periods... + + // SMBxLCNT >= T{min_SCL} * (T{min_SCL_low} / (T{min_SCL_low} + T{min_SCL_high})) * SMB_CLK - 1 + // >= (T{min_SCL_low} / T{min_SCL}) * SMB_CLK / I2C_CLK - 1 + + // SMBxHCNT >= T{min_SCL} * (T{min_SCL_high} / (T{min_SCL_low} + T{min_SCL_high})) * SMB_CLK - 8 + // >= (T{min_SCL_high} / T{min_SCL}) * SMB_CLK / I2C_CLK - 8 + + uint32_t high_reg, low_reg; + uint32_t high_count, low_count; + uint32_t hold_count, setup_count; + + // Level hold times: + + // Standard Fast + // SCL low 4.7us 1.3us + // SCL high 4.0us 0.6us + + // SCL period 8.7us 1.9us = + + if (i2c_clk <= 100) // 100 kHz + { + low_count = (smb_clk * 47) / (i2c_clk * 87) - 1; + high_count = (smb_clk * 40) / (i2c_clk * 87) - 8; + low_reg = Std_low_count; + high_reg = Std_high_count; + } + else + { + low_count = (smb_clk * 13) / (i2c_clk * 19) - 1; + high_count = (smb_clk * 6) / (i2c_clk * 19) - 8; + low_reg = Fast_low_count; + high_reg = Fast_high_count; + } + + // Minimum counts are 8 and 6 for low and high respectively. + + _regs[low_reg] = low_count < 8 ? 8 : low_count; + _regs[high_reg] = high_count < 6 ? 6 : high_count; + + // Data hold and setup times: + + // Standard Fast + // t{HD;DAT} 300ns 300ns + // t{SU;DAT} 250ns 100ns + + // T{delay} = (SMBSDAHD + 1) * T{SMB_CLK} + // SMBSDAHD = T{delay} / T{SMB_CLK} - 1 + // SMBSDAHD = SMB_CLK * T{delay} - 1 + + hold_count = (smb_clk * 300) / 1000000 - 1; + + _regs[Smb_sda_hold_time] = (_regs[Smb_sda_hold_time] & ~Smb_hold_mask) | + (hold_count > 0 ? Smb_hold_enable : Smb_hold_disable) | + (hold_count < 255 ? hold_count : 255); + + // T{delay} = (SMBSDASU - 1) * T{SMB_CLK} + // SMBSDASU = T{delay} / T{SMB_CLK} + 1 + // SMBSDASU = SMB_CLK * T{delay} + 1 + + if (i2c_clk <= 100) + setup_count = (smb_clk * 250) / 1000000 + 1; + else + setup_count = (smb_clk * 100) / 1000000 + 1; + + _regs[Smb_sda_setup_time] = (_regs[Smb_sda_setup_time] & ~Smb_setup_mask) | + (setup_count < 255 ? setup_count : 255); +} + +// Set the target address and enable transfer. +// NOTE: Only supporting 7-bit addresses currently. + +void +I2c_jz4780_channel::set_target(uint8_t address) +{ + disable(); + set_frequency(); + _regs[Smb_target_address] = address & Smb_target_7bits; + enable(); + init_parameters(); + queued = 0; +} + + + +// Reset interrupt flags upon certain conditions. + +void +I2c_jz4780_channel::reset_flags() +{ + volatile uint32_t r; + + _regs[Int_mask] = 0; + + // Read from the register to clear interrupts. + + r = _regs[Int_combined_clear]; + (void) r; +} + +// Initialise interrupt flags and queue thresholds for reading and writing. + +void +I2c_jz4780_channel::init_parameters() +{ + // Handle read queue conditions for data, write queue conditions for commands. + + reset_flags(); + + _regs[Int_mask] = Int_rx_full | // read condition (reading needed) + Int_rx_of | // abort condition + Int_tx_empty | // write condition (writing needed) + Int_tx_abort; // abort condition + + _regs[Tx_fifo_thold] = 0; // write when 0 in queue + + // Make sure that the stop condition does not occur automatically. + + _regs[Smb_control] = _regs[Smb_control] | Smb_no_stop_empty; +} + + + +// Return whether the device is active. + +int +I2c_jz4780_channel::active() +{ + return _regs[Smb_status] & Smb_status_master_act; +} + +// Return whether data is available to receive. + +int +I2c_jz4780_channel::have_input() +{ + return _regs[Smb_status] & Smb_status_rx_nempty; +} + +// Return whether data is queued for sending. + +int +I2c_jz4780_channel::have_output() +{ + return !(_regs[Smb_status] & Smb_status_tx_empty); +} + +// Return whether data can be queued for sending. + +int +I2c_jz4780_channel::can_send() +{ + return _regs[Smb_status] & Smb_status_tx_nfull; +} + +// Return whether a receive operation has failed. + +int +I2c_jz4780_channel::read_failed() +{ + return _regs[Int_status] & Int_rx_of; +} + +// Return whether a send operation has failed. + +int +I2c_jz4780_channel::write_failed() +{ + return _regs[Int_status] & Int_tx_abort; +} + + + +// Send read commands for empty queue entries. + +void +I2c_jz4780_channel::queue_reads() +{ + unsigned remaining = _total - _reqpos; + unsigned can_queue = Smb_fifo_limit - queued + 1; + + if (!remaining) + { + _regs[Smb_data_command] = Smb_command_read; + return; + } + + // Keep the number of reads in progress below the length of the read queue. + + if (!can_queue) + { + //printf("remaining=%d queued=%d\n", remaining, queued); + return; + } + + if (remaining < can_queue) + can_queue = remaining; + + // Queue read requests for any remaining queue entries. + + for (unsigned i = 0; i < can_queue; i++) + _regs[Smb_data_command] = Smb_command_read; + + // Track queued messages and requested positions. + + queued += can_queue; + _reqpos += can_queue; + + if (_total == _reqpos) + printf("Written %d read requests.\n", _reqpos); +} + +// Send write commands for empty queue entries. + +void +I2c_jz4780_channel::queue_writes(uint8_t buf[], unsigned *pos, unsigned total) +{ + // Queue write requests for any remaining queue entries. + + while ((*pos < total) && can_send() && !write_failed()) + { + _regs[Smb_data_command] = Smb_command_write | buf[*pos]; + (*pos)++; + } +} + +// Store read command results from the queue. + +void +I2c_jz4780_channel::store_reads() +{ + int have_read = 0; + + // Read any input and store it in the buffer. + + while (have_input() && (_pos < _total)) + { + _buf[_pos] = _regs[Smb_data_command] & 0xff; + queued--; + _pos++; + + have_read = 1; + } + + // Update the threshold to be notified of any reduced remaining amount. + + if (have_read) + set_read_threshold(); + + //printf("Read to %d, still %d queued.\n", _pos, queued); +} + +// Read from the target device. + +void +I2c_jz4780_channel::start_read(uint8_t buf[], unsigned total) +{ + printf("intst=%x\n", (uint32_t) _regs[Int_status]); + + _buf = buf; + _total = total; + _pos = 0; + _reqpos = 0; + _fail = 0; + _stop = 0; + + set_read_threshold(); +} + +void +I2c_jz4780_channel::set_read_threshold() +{ + unsigned remaining = _total - _pos; + + if (!remaining) + return; + + if (remaining <= Smb_fifo_limit) + _regs[Rx_fifo_thold] = remaining - 1; // read all remaining + else + _regs[Rx_fifo_thold] = Smb_fifo_limit - 1; // read to limit + + //printf("rxthold=%d\n", (uint32_t) _regs[Rx_fifo_thold] + 1); +} + +void +I2c_jz4780_channel::read() +{ + if (read_failed() || write_failed()) + { + printf("intst*=%x\n", (uint32_t) _regs[Int_status]); + printf("rxfifo=%d\n", (uint32_t) _regs[Rx_fifo_count] & 0x3f); + printf("smbabtsrc=%x\n", (uint32_t) _regs[Trans_abort_status0]); + _fail = 1; + return; + } + + //printf("rxfifo=%d\n", (uint32_t) _regs[Rx_fifo_count]); + //printf("intst=%x\n", (uint32_t) _regs[Int_status]); + + if (_pos < _total) + { + if (_regs[Int_status] & Int_rx_full) + store_reads(); + if (_regs[Int_status] & Int_tx_empty) + queue_reads(); + } + else + { + stop(); + _regs[Int_mask] = 0; + } +} + +int +I2c_jz4780_channel::read_done() +{ + return _pos == _total; +} + +unsigned +I2c_jz4780_channel::have_read() +{ + return _pos; +} + +int +I2c_jz4780_channel::read_incomplete() +{ + return _fail; +} + +// Write to the target device. + +void +I2c_jz4780_channel::write(uint8_t buf[], unsigned total) +{ + unsigned pos = 0; + + while ((pos < total) && !write_failed()) + { + queue_writes(buf, &pos, total); + } +} + +// Explicitly stop communication. + +void +I2c_jz4780_channel::stop() +{ + if (_stop) + return; + + _regs[Smb_control] = _regs[Smb_control] & ~Smb_no_stop_empty; + _stop = 1; + printf("Stop sent.\n"); +} + + + +// Initialise the I2C controller. + +I2c_jz4780_chip::I2c_jz4780_chip(l4_addr_t start, l4_addr_t end, + Cpm_jz4780_chip *cpm, + uint32_t frequency) +: _start(start), _end(end), _cpm(cpm), _frequency(frequency) +{ +} + +// Obtain a channel object. + +I2c_jz4780_channel * +I2c_jz4780_chip::get_channel(uint8_t channel) +{ + l4_addr_t block = _start + channel * Smb_block_offset; + + if (block < _end) + { + _cpm->start_i2c(channel); + return new I2c_jz4780_channel(block, _cpm, _frequency); + } + else + throw -L4_EINVAL; +} + + + +// C language interface functions. + +void *jz4780_i2c_init(l4_addr_t start, l4_addr_t end, void *cpm, uint32_t frequency) +{ + return (void *) new I2c_jz4780_chip(start, end, static_cast(cpm), frequency); +} + +void *jz4780_i2c_get_channel(void *i2c, uint8_t channel) +{ + return static_cast(i2c)->get_channel(channel); +} + +void jz4780_i2c_set_target(void *i2c_channel, uint8_t addr) +{ + static_cast(i2c_channel)->set_target(addr); +} + +void jz4780_i2c_start_read(void *i2c_channel, uint8_t buf[], unsigned total) +{ + static_cast(i2c_channel)->start_read(buf, total); +} + +void jz4780_i2c_read(void *i2c_channel) +{ + static_cast(i2c_channel)->read(); +} + +int jz4780_i2c_read_done(void *i2c_channel) +{ + return static_cast(i2c_channel)->read_done(); +} + +unsigned jz4780_i2c_have_read(void *i2c_channel) +{ + return static_cast(i2c_channel)->have_read(); +} + +int jz4780_i2c_read_incomplete(void *i2c_channel) +{ + return static_cast(i2c_channel)->read_incomplete(); +} + +void jz4780_i2c_write(void *i2c_channel, uint8_t buf[], unsigned total) +{ + static_cast(i2c_channel)->write(buf, total); +} + +void jz4780_i2c_stop(void *i2c_channel) +{ + static_cast(i2c_channel)->stop(); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/include/keypad.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/include/keypad.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,48 @@ +/* + * Keypad description access. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +#ifdef __cplusplus + +class Keypad +{ +public: + virtual int columns(void) = 0; + virtual int rows(void) = 0; + virtual int code(int column, int row) = 0; + static Keypad *get_keypad(); +}; + +#endif + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *keypad_get(void); +int keypad_columns(void *keypad); +int keypad_rows(void *keypad); +int keypad_code(void *keypad, int column, int row); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := common letux400 qi_lb60 + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/src/common/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/src/common/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libkeypad.o.a +PC_FILENAME := libdrivers-keypad + +SRC_CC := keypad.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/keypad/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/src/common/keypad.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/src/common/keypad.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,50 @@ +/* + * General keypad mapping support. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "keypad.h" + +/* Obtain the common instance. */ + +void *keypad_get(void) +{ + return reinterpret_cast(Keypad::get_keypad()); +} + +/* Number of keypad columns. */ + +int keypad_columns(void *keypad) +{ + return static_cast(keypad)->columns(); +} + +/* Number of keypad rows, used by each value in the column array. */ + +int keypad_rows(void *keypad) +{ + return static_cast(keypad)->rows(); +} + +/* Keycode accessors. */ + +int keypad_code(void *keypad, int column, int row) +{ + return static_cast(keypad)->code(column, row); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/src/letux400/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/src/letux400/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libkeypad_letux400.o.a +PC_FILENAME := libdrivers-keypad-letux400 + +SRC_CC := keypad-letux400.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/keypad/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/src/letux400/keypad-letux400.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/src/letux400/keypad-letux400.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,105 @@ +/* + * Letux 400 key mapping. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "keypad.h" +#include + +enum Jz4730_keypad_gpio +{ + Jz4730_keypad_gpio_inputs_count = 8, + Jz4730_keypad_gpio_outputs_count = 17, +}; + +class Keypad_letux400 : public Keypad +{ + /* Keycode definitions. */ + + const int keycodes[Jz4730_keypad_gpio_inputs_count][Jz4730_keypad_gpio_outputs_count] = { + + {L4RE_KEY_PAUSE, L4RE_KEY_Q, L4RE_KEY_W, L4RE_KEY_E, L4RE_KEY_R, L4RE_KEY_U, + L4RE_KEY_I, L4RE_KEY_O, 0, 0, 0, L4RE_KEY_P, 0, 0, 0, 0}, + + {0, L4RE_KEY_TAB, L4RE_KEY_CAPSLOCK, L4RE_KEY_F3, L4RE_KEY_T, L4RE_KEY_Y, + L4RE_KEY_RIGHTBRACE, L4RE_KEY_F7, 0, L4RE_KEY_BACKSPACE, 0, + L4RE_KEY_LEFTBRACE, L4RE_KEY_SLEEP, 0, 0, 0, L4RE_KEY_LEFTSHIFT}, + + {0, L4RE_KEY_A, L4RE_KEY_S, L4RE_KEY_D, L4RE_KEY_F, L4RE_KEY_J, L4RE_KEY_K, + L4RE_KEY_L, 0, 0, 0, L4RE_KEY_SEMICOLON, 0, 0, 0, L4RE_KEY_UP, + L4RE_KEY_RIGHTSHIFT}, + + {0, L4RE_KEY_ESC, L4RE_KEY_BACKSLASH /* left */, L4RE_KEY_F4, L4RE_KEY_G, + L4RE_KEY_H, L4RE_KEY_F6, 0, L4RE_KEY_SPACE, 0, L4RE_KEY_LEFTALT, + L4RE_KEY_APOSTROPHE, 0, 0, 0, L4RE_KEY_DOWN, 0}, + + {0, L4RE_KEY_Z, L4RE_KEY_X, L4RE_KEY_C, L4RE_KEY_V, L4RE_KEY_M, + L4RE_KEY_COMMA, L4RE_KEY_DOT, L4RE_KEY_NUMLOCK, L4RE_KEY_ENTER, 0, + L4RE_KEY_BACKSLASH /* right */, 0, 0, 0, L4RE_KEY_LEFT, 0}, + + {0, 0, 0, 0, L4RE_KEY_B, L4RE_KEY_N, 0, L4RE_KEY_MENU, + 0, 0, 0, L4RE_KEY_SLASH, 0, 0, 0, L4RE_KEY_RIGHT, 0}, + + {L4RE_KEY_LEFTCTRL, L4RE_KEY_GRAVE, 0, 0, L4RE_KEY_5, L4RE_KEY_6, + L4RE_KEY_EQUAL, L4RE_KEY_F8, L4RE_KEY_DELETE, L4RE_KEY_F9, 0, + L4RE_KEY_MINUS, 0, L4RE_KEY_F2, L4RE_KEY_INSERT, 0, L4RE_KEY_F1}, + + {L4RE_KEY_F5, L4RE_KEY_1, L4RE_KEY_2, L4RE_KEY_3, L4RE_KEY_4, L4RE_KEY_7, + L4RE_KEY_8, L4RE_KEY_9, 0, 0, L4RE_KEY_SYSRQ, L4RE_KEY_0, L4RE_KEY_F10, 0, + 0, 0, L4RE_KEY_FN} + }; + +public: + + /* Number of keypad columns. */ + + int columns() + { + return Jz4730_keypad_gpio_outputs_count; + } + + /* Number of keypad rows, used by each value in the column array. */ + + int rows() + { + return Jz4730_keypad_gpio_inputs_count; + } + + /* Keycode accessors. */ + + int code(int column, int row) + { + return keycodes[row][column]; + } + + /* Common instance. */ + + static Keypad_letux400 keypad; +}; + +/* The actual definition. */ + +Keypad_letux400 Keypad_letux400::keypad; + +/* Definition access. */ + +Keypad *Keypad::get_keypad() +{ + return &Keypad_letux400::keypad; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/src/qi_lb60/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/src/qi_lb60/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libkeypad_qi_lb60.o.a +PC_FILENAME := libdrivers-keypad-qi_lb60 + +SRC_CC := keypad-qi_lb60.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/keypad/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/keypad/src/qi_lb60/keypad-qi_lb60.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/keypad/src/qi_lb60/keypad-qi_lb60.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,99 @@ +/* + * Ben NanoNote key mapping. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "keypad.h" +#include + +enum Jz4740_keypad_gpio +{ + Jz4740_keypad_gpio_inputs_count = 8, + Jz4740_keypad_gpio_outputs_count = 8, +}; + +class Keypad_qi_lb60 : public Keypad +{ + /* Keycode definitions. */ + + const int keycodes[Jz4740_keypad_gpio_inputs_count][Jz4740_keypad_gpio_outputs_count] = { + + {L4RE_KEY_F1, L4RE_KEY_F2, L4RE_KEY_F3, L4RE_KEY_F4, L4RE_KEY_F5, + L4RE_KEY_F6, L4RE_KEY_F7, 0}, + + {L4RE_KEY_Q, L4RE_KEY_W, L4RE_KEY_E, L4RE_KEY_R, L4RE_KEY_T, L4RE_KEY_Y, + L4RE_KEY_U, L4RE_KEY_I}, + + {L4RE_KEY_A, L4RE_KEY_S, L4RE_KEY_D, L4RE_KEY_F, L4RE_KEY_G, L4RE_KEY_H, + L4RE_KEY_J, L4RE_KEY_K}, + + {L4RE_KEY_ESC, L4RE_KEY_Z, L4RE_KEY_X, L4RE_KEY_C, L4RE_KEY_V, L4RE_KEY_B, + L4RE_KEY_N, L4RE_KEY_M}, + + {L4RE_KEY_TAB, L4RE_KEY_CAPSLOCK /* D-Sh */, L4RE_KEY_BACKSLASH, + L4RE_KEY_APOSTROPHE, L4RE_KEY_COMMA, L4RE_KEY_DOT, L4RE_KEY_SLASH, + L4RE_KEY_UP}, + + {L4RE_KEY_O, L4RE_KEY_L, L4RE_KEY_EQUAL, L4RE_KEY_RIGHTALT /* Sym */, + L4RE_KEY_SPACE, L4RE_KEY_F13 /* Qi */, L4RE_KEY_RIGHTCTRL, L4RE_KEY_LEFT}, + + {L4RE_KEY_F8, L4RE_KEY_P, L4RE_KEY_BACKSPACE, L4RE_KEY_ENTER, + L4RE_KEY_VOLUMEUP, L4RE_KEY_VOLUMEDOWN, L4RE_KEY_DOWN, L4RE_KEY_RIGHT}, + + {L4RE_KEY_LEFTSHIFT, L4RE_KEY_LEFTALT, L4RE_KEY_FN, 0, 0, 0, 0, 0} + }; + +public: + + /* Number of keypad columns. */ + + int columns() + { + return Jz4740_keypad_gpio_outputs_count; + } + + /* Number of keypad rows, used by each value in the column array. */ + + int rows() + { + return Jz4740_keypad_gpio_inputs_count; + } + + /* Keycode accessors. */ + + int code(int column, int row) + { + return keycodes[row][column]; + } + + /* Common instance. */ + + static Keypad_qi_lb60 keypad; +}; + +/* The actual definition. */ + +Keypad_qi_lb60 Keypad_qi_lb60::keypad; + +/* Definition access. */ + +Keypad *Keypad::get_keypad() +{ + return &Keypad_qi_lb60::keypad; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR = ../../.. +L4DIR ?= $(PKGDIR)/../.. + +PC_FILENAME := libdrivers-lcd-headers + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/include/lcd-jz4740-config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/include/lcd-jz4740-config.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,85 @@ +/* + * LCD configuration value definitions for the JZ4740 and related SoCs. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum Jz4740_lcd_config_bits : unsigned +{ + Jz4740_lcd_config_lcd_pin = 31, /* LCDPIN */ + Jz4740_lcd_config_tv_pal_halfline = 30, /* JZ4780: TVEPEH */ + Jz4740_lcd_config_desc_8_word = 28, /* JZ4780: NEWDES */ + Jz4740_lcd_config_tv_enable = 26, /* JZ4780: TVEN */ + Jz4740_lcd_config_underrun_recover = 25, /* JZ4780: RECOVER */ + Jz4740_lcd_config_ps_disable = 23, /* PSM */ + Jz4740_lcd_config_cls_disable = 22, /* CLSM */ + Jz4740_lcd_config_spl_disable = 21, /* SPLM */ + Jz4740_lcd_config_rev_disable = 20, /* REVM */ + Jz4740_lcd_config_hsync_mod_disable = 19, /* HSYNM (hsync polarity choice) */ + Jz4740_lcd_config_pclock_mod_disable = 18, /* PCLKM (dot/pixel clock polarity choice) */ + Jz4740_lcd_config_data_inverse = 17, /* INVDAT (inverse output data) */ + Jz4740_lcd_config_sync_input = 16, /* SYNDIR (hsync/vsync direction) */ + Jz4740_lcd_config_ps_reset = 15, /* PSP */ + Jz4740_lcd_config_cls_reset = 14, /* CLSP */ + Jz4740_lcd_config_spl_reset = 13, /* SPLP */ + Jz4740_lcd_config_rev_reset = 12, /* REVP */ + Jz4740_lcd_config_hsync_active_low = 11, /* HSP (hsync polarity) */ + Jz4740_lcd_config_pclock_fall_edge = 10, /* PCP (dot/pixel clock polarity) */ + Jz4740_lcd_config_de_active_low = 9, /* DEP (data enable polarity) */ + Jz4740_lcd_config_vsync_fall_edge = 8, /* VSP (vsync polarity) */ + Jz4740_lcd_config_bpp = 6, /* 16/18/24bpp selection for generic TFT */ + Jz4740_lcd_config_stn_pins = 4, /* PDW (STN pins utilisation) */ + Jz4740_lcd_config_mode = 0, +}; + +enum Jz4740_lcd_bpp_values : unsigned +{ + Jz4740_lcd_bpp_16 = 0, + Jz4740_lcd_bpp_24 = 1, /* JZ4780 */ + Jz4740_lcd_bpp_18 = 2, +}; + +enum Jz4740_lcd_modes : unsigned +{ + Jz4740_lcd_mode_tft_generic = 0, /* parallel 16/18/24-bit panel */ + Jz4740_lcd_mode_tft_sharp = 1, + Jz4740_lcd_mode_tft_casio = 2, + Jz4740_lcd_mode_tft_samsung = 3, + Jz4740_lcd_mode_ccir656_nonint = 4, /* non-interlaced (TV out) */ + Jz4740_lcd_mode_ccir656_int = 6, /* interlaced (TV out) */ + Jz4740_lcd_mode_stn_single_colour = 8, /* single == one panel */ + Jz4740_lcd_mode_stn_single_mono = 9, + Jz4740_lcd_mode_stn_dual_colour = 10, /* dual == two panels */ + Jz4740_lcd_mode_stn_dual_mono = 11, + Jz4740_lcd_mode_tft_serial = 12, /* serial 8-bit panel */ + Jz4740_lcd_mode_lcm = 13, /* JZ4780 */ +}; + +enum Jz4740_lcd_config_values : unsigned +{ + Jz4740_lcd_de_positive = 0 << Jz4740_lcd_config_de_active_low, + Jz4740_lcd_de_negative = 1 << Jz4740_lcd_config_de_active_low, + Jz4740_lcd_pclock_positive = 0 << Jz4740_lcd_config_pclock_fall_edge, + Jz4740_lcd_pclock_negative = 1 << Jz4740_lcd_config_pclock_fall_edge, + Jz4740_lcd_hsync_positive = 0 << Jz4740_lcd_config_hsync_active_low, + Jz4740_lcd_hsync_negative = 1 << Jz4740_lcd_config_hsync_active_low, + Jz4740_lcd_vsync_positive = 0 << Jz4740_lcd_config_vsync_fall_edge, + Jz4740_lcd_vsync_negative = 1 << Jz4740_lcd_config_vsync_fall_edge, +}; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/include/lcd-jz4740-panel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/include/lcd-jz4740-panel.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,53 @@ +/* + * LCD panel definitions for the JZ4740 and related SoCs. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +/* Panel configuration details. */ + +struct Jz4740_lcd_panel +{ + uint32_t config; /* LCD configuration */ + + /* Display dimensions in pixels. */ + + uint32_t width, height; + uint32_t bpp; /* bits per pixel */ + + /* Display timing information. */ + + uint32_t frame_rate; /* frame clock frequency (Hz) */ + + /* Horizontal and vertical sync widths. */ + + uint32_t hsync; /* in pixel clock periods */ + uint32_t vsync; /* in line periods */ + + /* Inactive line region sizes before/after line data (in pixel clock periods). */ + + uint32_t line_start, line_end; /* similar to horizontal back porch, front porch */ + + /* Inactive frame region sizes before/after frame data (in line periods). */ + + uint32_t frame_start, frame_end; /* vertical back porch, front porch */ +}; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/include/lcd-jz4740.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/include/lcd-jz4740.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,155 @@ +/* + * LCD peripheral support for the JZ4740 and related SoCs. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "lcd.h" +#include "lcd-jz4740-panel.h" + +#include + +#include + +/* Descriptor referenced by the DMA mechanism. */ + +struct Jz4740_lcd_descriptor +{ + struct Jz4740_lcd_descriptor *next; /* FDADR: frame descriptor address */ + uint32_t source; /* FSADR: frame source address */ + uint32_t identifier; /* FIDR: frame identifier */ + uint32_t command; /* CMD: command */ +}; + + + +/* C++ language interface. */ + +#ifdef __cplusplus + +#include + +/* General JZ4740 LCD controller support. */ + +class Lcd_jz4740_chip : public Lcd_chip +{ +private: + Hw::Register_block<32> _regs; + Jz4740_lcd_panel *_panel; + int _burst_size; + + /* Control register value calculation. */ + + uint32_t _control_bpp(); + uint32_t _control_panel(); + uint32_t _control_stn_frc(); + uint32_t _control_transfer(); + + /* Panel mode access. */ + + uint32_t _mode(); + + /* Panel initialisation. */ + + void _init_stn(); + void _init_tft(); + void _init_panel(); + + /* Descriptor initialisation. */ + + void _set_descriptor(struct Jz4740_lcd_descriptor &desc, l4_addr_t source, + l4_size_t size, struct Jz4740_lcd_descriptor *next, + uint32_t flags = 0); + +public: + Lcd_jz4740_chip(l4_addr_t addr, Jz4740_lcd_panel *panel); + + struct Jz4740_lcd_panel *get_panel(); + + /* Peripheral control. */ + + void disable(); + void disable_quick(); + void enable(); + + /* Peripheral properties. */ + + int get_pixel_clock(); + + /* Panel properties. */ + + int get_panels(); + int have_stn_panel(); + int have_colour_stn(); + int have_serial_tft(); + + /* Memory properties. */ + + l4_size_t get_line_size(); + l4_size_t get_screen_size(); + l4_size_t get_aligned_size(); + l4_size_t get_palette_size(); + l4_size_t get_aligned_palette_size(); + + /* Memory properties for allocation purposes. */ + + l4_size_t get_total_size(); + l4_size_t get_descriptors_size(); + + /* Memory region access. */ + + l4_addr_t get_palette(l4_addr_t screen); + l4_addr_t get_framebuffer(int panel, l4_addr_t screen); + + /* Convenience methods. */ + + void init_palette(l4_addr_t palette); + + /* Configuration. */ + + void config(struct Jz4740_lcd_descriptor *desc_vaddr, + struct Jz4740_lcd_descriptor *desc_paddr, + l4_addr_t fb_paddr); +}; + +#endif + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4740_lcd_init(l4_addr_t lcd_base, struct Jz4740_lcd_panel *panel); + +void jz4740_lcd_config(void *lcd, struct Jz4740_lcd_descriptor *desc_vaddr, + struct Jz4740_lcd_descriptor *desc_paddr, + l4_addr_t fb_paddr); + +void jz4740_lcd_disable(void *lcd); +void jz4740_lcd_disable_quick(void *lcd); +void jz4740_lcd_enable(void *lcd); + +l4_addr_t jz4740_lcd_get_palette(void *lcd, l4_addr_t base); +int jz4740_lcd_get_pixel_clock(void *lcd); + +void jz4740_lcd_init_palette(void *lcd, l4_addr_t palette); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/include/lcd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/include/lcd.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,30 @@ +/* + * LCD peripheral support. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +class Lcd_chip +{ +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := jz4740 + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/src/jz4740/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/src/jz4740/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = liblcd_jz4740.o.a +PC_FILENAME := libdrivers-lcd-jz4740 + +SRC_CC := lcd-jz4740.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/lcd/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/lcd/src/jz4740/lcd-jz4740.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/lcd/src/jz4740/lcd-jz4740.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,749 @@ +/* + * LCD peripheral support for the JZ4740 and related SoCs. + * + * Copyright (C) Xiangfu Liu + * Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "lcd-jz4740.h" +#include "lcd-jz4740-config.h" + +#include + +enum Regs : unsigned +{ + Lcd_config = 0x000, // LCD_CFG + Lcd_vsync = 0x004, // LCD_VSYNC + Lcd_hsync = 0x008, // LCD_HSYNC + Vertical_area = 0x00c, // LCD_VAT + Display_hlimits = 0x010, // LCD_DAH + Display_vlimits = 0x014, // LCD_DAV + Lcd_ps = 0x018, // LCD_PS + Lcd_cls = 0x01c, // LCD_CLS + Lcd_spl = 0x020, // LCD_SPL + Lcd_rev = 0x024, // LCD_REV + Lcd_control = 0x030, // LCD_CTRL + Lcd_status = 0x034, // LCD_STATE + Lcd_irq_id = 0x038, // LCD_IID + Desc_address_0 = 0x040, // LCD_DA0 + Source_address_0 = 0x044, // LCD_SA0 + Frame_id_0 = 0x048, // LCD_FID0 + Command_0 = 0x04c, // LCD_CMD0 + Desc_address_1 = 0x050, // LCD_DA1 + Source_address_1 = 0x054, // LCD_SA1 + Frame_id_1 = 0x058, // LCD_FID1 + Command_1 = 0x05c, // LCD_CMD1 +}; + +// Lcd_config descriptions. + +enum Config_values : unsigned +{ + Config_stn_pins_mask = 0x3, + Config_mode_mask = 0xf, +}; + +// Field positions for registers employing two values, with the first typically +// being the start value and the second being an end value. + +enum Value_pair_bits : unsigned +{ + Value_first = 16, + Value_second = 0, +}; + +// Vertical_area bits. + +enum Vertical_area_values : unsigned +{ + Vertical_area_horizontal_size = Value_first, // sum of display and blank regions (dot/pixel clock periods) + Vertical_area_vertical_size = Value_second, // sum of display and blank regions (line periods) +}; + +// Lcd_control descriptions. + +enum Control_bits : unsigned +{ + Control_burst_length = 28, // BST (burst length selection) + Control_rgb_mode = 27, // RGB (RGB mode) + Control_out_underrun = 26, // OFUP (output FIFO underrun protection) + Control_frc_algorithm = 24, // FRC (STN FRC algorithm selection) + Control_palette_delay = 16, // PDD (load palette delay counter) + Control_frame_end_irq_mask = 13, // EOFM (end of frame interrupt mask) + Control_frame_start_irq_mask = 12, // SOFM (start of frame interrupt mask) + Control_out_underrun_irq_mask = 11, // OFUM (output FIFO underrun interrupt mask) + Control_in0_underrun_irq_mask = 10, // IFUM0 (input FIFO 0 underrun interrupt mask) + Control_in1_underrun_irq_mask = 9, // IFUM1 (input FIFO 1 underrun interrupt mask) + Control_disabled_irq_mask = 8, // LDDM (LCD disable done interrupt mask) + Control_quick_disabled_irq_mask = 7, // QDM (LCD quick disable done interrupt mask) + Control_endian_select = 6, // BEDN (endian selection) + Control_bit_order = 5, // PEDN (bit order in bytes) + Control_disable = 4, // DIS (disable controller) + Control_enable = 3, // ENA (enable controller) + Control_bpp = 0, // BPP (bits per pixel) +}; + +enum Burst_length_values : unsigned +{ + Burst_length_4 = 0, // 4 word + Burst_length_8 = 1, // 8 word + Burst_length_16 = 2, // 16 word + + // JZ4780 extensions. + + Burst_length_32 = 3, // 32 word + Burst_length_64 = 4, // 64 word + Burst_length_mask = 0x7, +}; + +enum Rgb_mode_values : unsigned +{ + Rgb_mode_565 = 0, + Rgb_mode_555 = 1, + Rgb_mode_mask = 0x1, +}; + +enum Frc_algorithm_values : unsigned +{ + Frc_greyscales_16 = 0, + Frc_greyscales_4 = 1, + Frc_greyscales_2 = 2, + Frc_greyscales_mask = 0x3, +}; + +enum Control_bpp_values : unsigned +{ + Control_bpp_1bpp = 0, + Control_bpp_2bpp = 1, + Control_bpp_4bpp = 2, + Control_bpp_8bpp = 3, + Control_bpp_15bpp = 4, + Control_bpp_16bpp = 4, + Control_bpp_18bpp = 5, + Control_bpp_24bpp = 5, + Control_bpp_24bpp_comp = 6, + Control_bpp_30bpp = 7, + Control_bpp_32bpp = 7, + Control_bpp_mask = 0x7, +}; + +// Command descriptions. + +enum Command_bits : unsigned +{ + Command_frame_start_irq = 31, // SOFINT (start of frame interrupt) + Command_frame_end_irq = 30, // EOFINT (end of frame interrupt) + Command_lcm_command = 29, // JZ4780: CMD (LCM command/data via DMA0) + Command_palette_buffer = 28, // PAL (descriptor references palette, not display data) + Command_frame_compressed = 27, // JZ4780: COMPEN (16/24bpp compression enabled) + Command_frame_enable = 26, // JZ4780: FRM_EN + Command_field_even = 25, // JZ4780: FIELD_SEL (interlace even field) + Command_16x16_block = 24, // JZ4780: 16x16BLOCK (fetch data by 16x16 block) + Command_buffer_length = 0, // LEN +}; + +enum Command_values : unsigned +{ + Command_buffer_length_mask = 0x00ffffff, +}; + + + +// Utility functions. + +// Round values up according to the resolution. + +static uint32_t align(uint32_t value, uint32_t resolution) +{ + return (value + (resolution - 1)) & ~(resolution - 1); +} + +// Value pair encoding. + +static uint32_t encode_pair(uint32_t start, uint32_t end) +{ + return (start << Value_first) | (end << Value_second); +} + +// RGB conversions. + +static uint16_t rgb8_to_rgb16(uint8_t rgb) +{ + return ((((rgb & 0xe0) >> 5) * 4) << 11) | ((((rgb & 0x1c) >> 2) * 9) << 6) | ((rgb & 0x03) * 10); +} + +static uint16_t rgb4_to_rgb16(uint8_t rgb) +{ + return ((((rgb & 8) >> 3) * 0x1f) << 11) | ((((rgb & 6) >> 1) * 0x15) << 5) | ((rgb & 1) * 0x1f); +} + + + + +// If implemented as a Hw::Device, various properties would be +// initialised in the constructor and obtained from the device tree +// definitions. + +Lcd_jz4740_chip::Lcd_jz4740_chip(l4_addr_t addr, Jz4740_lcd_panel *panel) +: _panel(panel) +{ + _regs = new Hw::Mmio_register_block<32>(addr); + _burst_size = 16; // 16-word burst size + + // add_cid("lcd"); + // add_cid("lcd-jz4740"); +} + +struct Jz4740_lcd_panel * +Lcd_jz4740_chip::get_panel() +{ + return _panel; +} + +void +Lcd_jz4740_chip::disable() +{ + // Set the disable bit for normal shutdown. + + _regs[Lcd_control] = _regs[Lcd_control] | (1 << Control_disable); +} + +void +Lcd_jz4740_chip::disable_quick() +{ + // Clear the enable bit for quick shutdown. + + _regs[Lcd_control] = _regs[Lcd_control] & ~(1 << Control_enable); +} + +void +Lcd_jz4740_chip::enable() +{ + // Clear the disable bit and set the enable bit. + + _regs[Lcd_control] = (_regs[Lcd_control] & ~(1 << Control_disable)) | (1 << Control_enable); +} + +// Calculate and return the pixel clock frequency. + +int +Lcd_jz4740_chip::get_pixel_clock() +{ + int pclk, multiplier; + + // Serial mode: 3 pixel clock cycles per pixel (one per channel). + // Parallel mode: 1 pixel clock cycle per pixel. + + multiplier = have_serial_tft() ? 3 : 1; + + // Derive pixel clock rate from frame rate. + // This multiplies the number of pixel periods in a line by the number of + // lines in a frame, thus obtaining the number of such periods in a frame. + // Multiplying this result with the frame rate yields the pixel frequency. + + pclk = _panel->frame_rate * + (_panel->width * multiplier + + _panel->hsync + _panel->line_start + _panel->line_end) * + (_panel->height + + _panel->vsync + _panel->frame_start + _panel->frame_end); + + // STN panel adjustments. + + if (have_stn_panel()) + { + // Colour STN panels apparently need to be driven at three times the rate. + + if (have_colour_stn()) pclk = (pclk * 3); + + // Reduce the rate according to the width of the STN connection. + // Since the pins setting employs log2(pins), a shift by this value is + // equivalent to a division by the number of pins. + + pclk = pclk >> ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins); + + // Divide the rate by the number of panels. + + pclk /= get_panels(); + } + + return pclk; +} + + + +// Return the panel mode. + +uint32_t +Lcd_jz4740_chip::_mode() +{ + return _panel->config & Config_mode_mask; +} + +// Return the number of panels available. + +int +Lcd_jz4740_chip::get_panels() +{ + uint32_t mode = _mode(); + + return (mode == Jz4740_lcd_mode_stn_dual_colour) || + (mode == Jz4740_lcd_mode_stn_dual_mono) ? 2 : 1; +} + +// Return whether the panel is STN. + +int +Lcd_jz4740_chip::have_stn_panel() +{ + uint32_t mode = _mode(); + + return ((mode == Jz4740_lcd_mode_stn_single_colour) || + (mode == Jz4740_lcd_mode_stn_dual_colour) || + (mode == Jz4740_lcd_mode_stn_single_mono) || + (mode == Jz4740_lcd_mode_stn_dual_mono)); +} + +// Return whether the panel is colour STN. + +int +Lcd_jz4740_chip::have_colour_stn() +{ + uint32_t mode = _mode(); + + return ((mode == Jz4740_lcd_mode_stn_single_colour) || + (mode == Jz4740_lcd_mode_stn_dual_colour)); +} + +// Return whether the panel is colour STN. + +int +Lcd_jz4740_chip::have_serial_tft() +{ + return _mode() == Jz4740_lcd_mode_tft_serial; +} + + + +// Return the line memory size. + +l4_size_t +Lcd_jz4740_chip::get_line_size() +{ + // Lines must be aligned to a word boundary. + + return align((_panel->width * _panel->bpp) / 8, sizeof(uint32_t)); +} + +// Return the screen memory size. + +l4_size_t +Lcd_jz4740_chip::get_screen_size() +{ + return get_line_size() * _panel->height; +} + +// Return the aligned size for the DMA transfer. + +l4_size_t +Lcd_jz4740_chip::get_aligned_size() +{ + return align(get_screen_size(), _burst_size * sizeof(uint32_t)); +} + +// Return the size of the palette. + +l4_size_t +Lcd_jz4740_chip::get_palette_size() +{ + // No palette for modes with more than eight bits per pixel. + + if (_panel->bpp > 8) return 0; + + // Get the size of a collection of two-byte entries, one per colour. + + return (1 << (_panel->bpp)) * sizeof(uint16_t); +} + +// Return the aligned size of the palette for the DMA transfer. + +l4_size_t +Lcd_jz4740_chip::get_aligned_palette_size() +{ + return align(get_palette_size(), _burst_size * sizeof(uint32_t)); +} + +// Return the total memory requirements of the framebuffers and palette. + +l4_size_t +Lcd_jz4740_chip::get_total_size() +{ + return get_aligned_size() * get_panels() + get_aligned_palette_size(); +} + +// Return the total memory requirements of any DMA descriptors. + +l4_size_t +Lcd_jz4740_chip::get_descriptors_size() +{ + return 3 * sizeof(struct Jz4740_lcd_descriptor); +} + + + +// Functions returning addresses of each data region. +// The base parameter permits the retrieval of virtual or physical addresses. + +l4_addr_t +Lcd_jz4740_chip::get_palette(l4_addr_t base) +{ + // Use memory at the end of the allocated region for the palette. + + return base + (get_panels() * get_aligned_size()) - get_aligned_palette_size(); +} + +l4_addr_t +Lcd_jz4740_chip::get_framebuffer(int panel, l4_addr_t base) +{ + // Framebuffers for panels are allocated at the start of the region. + + return base + (panel * get_aligned_size()); +} + + + +// Palette initialisation. + +void +Lcd_jz4740_chip::init_palette(l4_addr_t palette) +{ + uint8_t colours = 1 << (_panel->bpp); + uint16_t *entry = (uint16_t *) palette; + uint16_t *end = entry + colours; + uint8_t value = 0; + + while (entry < end) + { + switch (_panel->bpp) + { + case 4: + *entry = rgb4_to_rgb16(value); + break; + + case 8: + *entry = rgb8_to_rgb16(value); + break; + + default: + break; + } + + value++; + entry++; + } +} + + + +// Return colour depth control value. +// NOTE: Not supporting JZ4780 options. + +uint32_t +Lcd_jz4740_chip::_control_bpp() +{ + switch (_panel->bpp) + { + case 1: return Control_bpp_1bpp; + case 2: return Control_bpp_2bpp; + case 3 ... 4: return Control_bpp_4bpp; + case 5 ... 8: return Control_bpp_8bpp; + case 9 ... 15: return Control_bpp_15bpp | (Rgb_mode_555 << Control_rgb_mode); + case 17 ... 18: return Control_bpp_18bpp; + case 19 ... 32: return Control_bpp_24bpp; + case 16: + default: return Control_bpp_16bpp; + } +} + +// Return a panel-related control value. + +uint32_t +Lcd_jz4740_chip::_control_panel() +{ + if (have_stn_panel()) + return _control_stn_frc(); + else + return 0; +} + +// Return a STN-related control value. + +uint32_t +Lcd_jz4740_chip::_control_stn_frc() +{ + if (_panel->bpp <= 2) + return Frc_greyscales_2; + if (_panel->bpp <= 4) + return Frc_greyscales_4; + return Frc_greyscales_16; +} + +// Return a transfer-related control value. + +uint32_t +Lcd_jz4740_chip::_control_transfer() +{ + uint32_t length; + + switch (_burst_size) + { + case 4: length = Burst_length_4; break; + case 8: length = Burst_length_8; break; + case 32: length = Burst_length_32; break; + case 64: length = Burst_length_64; break; + case 16: + default: length = Burst_length_16; break; + } + + return (length << Control_burst_length) | (1 << Control_out_underrun); +} + +// STN panel-specific initialisation. + +void +Lcd_jz4740_chip::_init_stn() +{ + // Divide the height by the number of panels. + + uint32_t height = _panel->height / get_panels(); + + // Since the value is log2(pins), 1 << value yields the number of pins. + + int pins = 1 << ((_panel->config & Config_stn_pins_mask) >> Jz4740_lcd_config_stn_pins); + + // Round parameters up to a multiple of the number of pins. + + uint32_t hsync = align(_panel->hsync, pins); + uint32_t line_start = align(_panel->line_start, pins); + uint32_t line_end = align(_panel->line_end, pins); + + // Define the start and end positions of visible data on a line and in a frame. + // Visible frame data is anchored at line zero, with the start region + // preceding this line (and thus appearing at the end of the preceding frame). + + uint32_t line_start_pos = line_start; + uint32_t line_end_pos = line_start_pos + _panel->width; + uint32_t frame_start_pos = 0; + uint32_t frame_end_pos = frame_start_pos + height; + + // Define sync pulse locations, with hsync occurring after the visible data. + + _regs[Lcd_hsync] = encode_pair(line_end_pos, line_end_pos + hsync); + _regs[Lcd_vsync] = encode_pair(0, _panel->vsync); + + // Set the display area and limits. + + _regs[Vertical_area] = encode_pair(line_end_pos + hsync + line_end, + frame_end_pos + _panel->vsync + _panel->frame_end + _panel->frame_start); + + _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos); + _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos); + + // Set the AC bias signal. + + _regs[Lcd_ps] = encode_pair(0, _panel->frame_start + height + _panel->vsync + _panel->frame_end); +} + +// TFT panel-specific initialisation. + +void +Lcd_jz4740_chip::_init_tft() +{ + // Define the start and end positions of visible data on a line and in a frame. + + uint32_t line_start_pos = _panel->line_start + _panel->hsync; + uint32_t line_end_pos = line_start_pos + _panel->width; + uint32_t frame_start_pos = _panel->frame_start + _panel->vsync; + uint32_t frame_end_pos = frame_start_pos + _panel->height; + + // Define sync pulse locations, with pulses appearing before visible data. + + _regs[Lcd_hsync] = encode_pair(0, _panel->hsync); + _regs[Lcd_vsync] = encode_pair(0, _panel->vsync); + + // Set the display area and limits. + + _regs[Vertical_area] = encode_pair(line_end_pos + _panel->line_end, + frame_end_pos + _panel->frame_end); + + _regs[Display_hlimits] = encode_pair(line_start_pos, line_end_pos); + _regs[Display_vlimits] = encode_pair(frame_start_pos, frame_end_pos); +} + +// Initialise the panel. +// NOTE: Only generic STN and TFT panels are supported. + +void +Lcd_jz4740_chip::_init_panel() +{ + if (have_stn_panel()) + _init_stn(); + else + switch (_mode()) + { + case Jz4740_lcd_mode_tft_generic: + case Jz4740_lcd_mode_tft_casio: + case Jz4740_lcd_mode_tft_serial: _init_tft(); + + default: break; + } +} + +// Initialise a DMA descriptor. + +void +Lcd_jz4740_chip::_set_descriptor(struct Jz4740_lcd_descriptor &desc, + l4_addr_t source, l4_size_t size, + struct Jz4740_lcd_descriptor *next, + uint32_t flags) +{ + // In the command, indicate the number of words from the source for transfer. + + desc.next = next; + desc.source = source; + desc.identifier = 0; + desc.command = ((size / sizeof(uint32_t)) & Command_buffer_length_mask) | flags; +} + + + +// Initialise the LCD controller with the memory, panel and framebuffer details. +// Any palette must be initialised separately using get_palette and init_palette. + +void +Lcd_jz4740_chip::config(struct Jz4740_lcd_descriptor *desc_vaddr, + struct Jz4740_lcd_descriptor *desc_paddr, + l4_addr_t fb_paddr) +{ + int have_palette = (_panel->bpp <= 8); + + // Provide the first framebuffer descriptor in single and dual modes. + // Flip back and forth between any palette and the framebuffer. + + _set_descriptor(desc_vaddr[0], get_framebuffer(0, fb_paddr), + get_screen_size(), + have_palette ? desc_paddr + 2 : desc_paddr); + + // Provide the second framebuffer descriptor only in dual-panel mode. + // Only employ this descriptor in the second DMA channel. + + if (get_panels() == 2) + _set_descriptor(desc_vaddr[1], get_framebuffer(1, fb_paddr), + get_screen_size(), + desc_paddr + 1); + + // Initialise palette descriptor details for lower colour depths. + + if (have_palette) + _set_descriptor(desc_vaddr[2], get_palette(fb_paddr), + get_palette_size(), + desc_paddr, + Command_palette_buffer); + + // Flush cached structure data. + + l4_cache_clean_data((unsigned long) desc_vaddr, + (unsigned long) desc_vaddr + get_descriptors_size()); + + // Configure DMA by setting frame descriptor addresses. + + // Provide the palette descriptor address first, if employed. + + _regs[Desc_address_0] = (uint32_t) (have_palette ? desc_paddr + 2 : desc_paddr); + + // Provide a descriptor for the second DMA channel in dual-panel mode. + + if (get_panels() == 2) + _regs[Desc_address_1] = (uint32_t) (desc_paddr + 1); + + // Initialise panel-related registers. + + _init_panel(); + + // Initialise the control and configuration registers. + + _regs[Lcd_control] = _control_panel() | _control_bpp() | _control_transfer(); + _regs[Lcd_config] = _panel->config; +} + + + +// C language interface functions. + +void * +jz4740_lcd_init(l4_addr_t lcd_base, struct Jz4740_lcd_panel *panel) +{ + return (void *) new Lcd_jz4740_chip(lcd_base, panel); +} + +void +jz4740_lcd_config(void *lcd, struct Jz4740_lcd_descriptor *desc_vaddr, + struct Jz4740_lcd_descriptor *desc_paddr, + l4_addr_t fb_paddr) +{ + static_cast(lcd)->config(desc_vaddr, desc_paddr, fb_paddr); +} + +void +jz4740_lcd_disable(void *lcd) +{ + static_cast(lcd)->disable(); +} + +void +jz4740_lcd_disable_quick(void *lcd) +{ + static_cast(lcd)->disable_quick(); +} + +void +jz4740_lcd_enable(void *lcd) +{ + static_cast(lcd)->enable(); +} + +int +jz4740_lcd_get_pixel_clock(void *lcd) +{ + return static_cast(lcd)->get_pixel_clock(); +} + +l4_addr_t +jz4740_lcd_get_palette(void *lcd, l4_addr_t base) +{ + return static_cast(lcd)->get_palette(base); +} + +void +jz4740_lcd_init_palette(void *lcd, l4_addr_t palette) +{ + static_cast(lcd)->init_palette(palette); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/pwm/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/pwm/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/pwm/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/pwm/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/pwm/include/pwm-jz4730.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/pwm/include/pwm-jz4730.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,79 @@ +/* + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +/* Value types. */ + +enum Jz4730_pwm_shutdown_mode +{ + Jz4730_pwm_shutdown_graceful = 0, + Jz4730_pwm_shutdown_abrupt = 1, +}; + + + +#ifdef __cplusplus + +#include + +/* A simple abstraction for accessing the PWM registers. */ + +class Pwm_jz4730_chip +{ +private: + l4_addr_t _start, _end; + Hw::Register_block<32> _regs; + +public: + Pwm_jz4730_chip(l4_addr_t start, l4_addr_t end); + + void disable(); + void enable(); + void set_shutdown_mode(enum Jz4730_pwm_shutdown_mode mode); + + void set_control(uint8_t control); + void set_duty(uint16_t duty); + void set_period(uint16_t period); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4730_pwm_init(l4_addr_t start, l4_addr_t end); + +void jz4730_pwm_disable(void *pwm); +void jz4730_pwm_enable(void *pwm); +void jz4730_pwm_set_shutdown_mode(void *pwm, enum Jz4730_pwm_shutdown_mode mode); + +void jz4730_pwm_set_control(void *pwm, uint8_t control); +void jz4730_pwm_set_duty(void *pwm, uint16_t duty); +void jz4730_pwm_set_period(void *pwm, uint16_t period); + +EXTERN_C_END diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/pwm/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/pwm/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libpwm.o.a +PC_FILENAME := libdrivers-pwm + +SRC_CC := jz4730.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/pwm/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/lib/pwm/src/jz4730.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/pwm/src/jz4730.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,158 @@ +/* + * Pulse width modulation peripheral support. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include "pwm-jz4730.h" + + + +enum Regs : unsigned +{ + Pwm_control = 0x000, // CTR + Pwm_period = 0x004, // PER + Pwm_duty = 0x008, // DUT +}; + +enum Control_bits : unsigned +{ + Pwm_enable = 7, + Pwm_abrupt_shutdown = 6, + Pwm_prescale_mask = 0x3f, +}; + +enum Duty_bits : unsigned +{ + Pwm_duty_full = 10, + Pwm_duty_mask = 0x3ff, +}; + +enum Period_bits : unsigned +{ + Pwm_period_mask = 0x3ff, +}; + + + +// If implemented as a Hw::Device, various properties would be +// initialised in the constructor and obtained from the device tree +// definitions. + +Pwm_jz4730_chip::Pwm_jz4730_chip(l4_addr_t start, l4_addr_t end) +: _start(start), _end(end) +{ + _regs = new Hw::Mmio_register_block<32>(_start); + + // add_cid("pwm"); + // add_cid("pwm-jz4730"); +} + +void +Pwm_jz4730_chip::set_control(uint8_t control) +{ + // This allows the setting of the actual control bits. + + _regs[Pwm_control] = control; +} + +void +Pwm_jz4730_chip::disable() +{ + _regs[Pwm_control] = _regs[Pwm_control] & ~(1 << Pwm_enable); +} + +void +Pwm_jz4730_chip::enable() +{ + _regs[Pwm_control] = _regs[Pwm_control] | (1 << Pwm_enable); +} + +void +Pwm_jz4730_chip::set_shutdown_mode(enum Jz4730_pwm_shutdown_mode mode) +{ + if (mode == Jz4730_pwm_shutdown_graceful) + _regs[Pwm_control] = _regs[Pwm_control] & ~(1 << Pwm_abrupt_shutdown); + else + _regs[Pwm_control] = _regs[Pwm_control] | (1 << Pwm_abrupt_shutdown); +} + +void +Pwm_jz4730_chip::set_duty(uint16_t duty) +{ + // This deselects full duty, if it were set. + // NOTE: A way of selecting full duty is required. + + _regs[Pwm_duty] = (_regs[Pwm_duty] & ~(Pwm_duty_mask | (1 << Pwm_duty_full))) | + (duty & Pwm_duty_mask); +} + +void +Pwm_jz4730_chip::set_period(uint16_t period) +{ + _regs[Pwm_period] = (_regs[Pwm_period] & ~Pwm_period_mask) | + (period & Pwm_period_mask); +} + + + + +// C language interface functions. + +void * +jz4730_pwm_init(l4_addr_t start, l4_addr_t end) +{ + return (void *) new Pwm_jz4730_chip(start, end); +} + +void +jz4730_pwm_disable(void *pwm) +{ + static_cast(pwm)->disable(); +} + +void +jz4730_pwm_enable(void *pwm) +{ + static_cast(pwm)->enable(); +} + +void +jz4730_pwm_set_shutdown_mode(void *pwm, enum Jz4730_pwm_shutdown_mode mode) +{ + static_cast(pwm)->set_shutdown_mode(mode); +} + +void +jz4730_pwm_set_control(void *pwm, uint8_t control) +{ + static_cast(pwm)->set_control(control); +} + +void +jz4730_pwm_set_duty(void *pwm, uint16_t duty) +{ + static_cast(pwm)->set_duty(duty); +} + +void +jz4730_pwm_set_period(void *pwm, uint16_t period) +{ + static_cast(pwm)->set_period(period); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +PC_FILENAME := libdevice-panel-ops + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/include/panel-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/include/panel-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,39 @@ +/* + * Panel client to access panel servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include + +#include + +class Panel_device_interface : public L4::Kobject_t +{ + L4_KOBJECT(Panel_device_interface) + +public: + int get_panel(uint8_t *data, unsigned long datalen) throw(); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/include/panel-ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/include/panel-ops.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,24 @@ +/* + * Panel server operations. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum { Panel_op_get_panel }; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/include/panel-server.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/include/panel-server.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,49 @@ +/* + * Common panel server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include +#include + +/* Server object to provide panel data access. */ + +class Panel_server : public L4::Server_object_t +{ +private: + void *_panel; + unsigned long _size; + +public: + /* Initialise the server with an opaque pointer to the panel data and the + size of the data. */ + + explicit Panel_server(void *panel, unsigned long size) + : _panel(panel), _size(size) + {} + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,9 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := client letux400 qi_lb60 server + +include $(L4DIR)/mk/subdir.mk + +letux400: server +qi_lb60: server diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_panel_client.o.a +PC_FILENAME := libdevice-panel-client + +SRC_CC := panel-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/panel/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/client/panel-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/client/panel-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,46 @@ +/* + * Panel client to access panel servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "panel-client.h" +#include "panel-ops.h" + +#include + +int +Panel_device_interface::get_panel(uint8_t *data, unsigned long datalen) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + int err = l4_error(s.call(cap(), Panel_op_get_panel)); + if (err) return err; + + // Obtain the message from the stream. + + unsigned long size = datalen; + s >> L4::Ipc::buf_cp_in(data, datalen); + + if (size != datalen) return -L4_EIO; + return L4_EOK; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/letux400/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/letux400/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_panel_letux400 +PC_FILENAME := devices-panel-letux400 + +SRC_CC := panel-letux400.cc + +PRIVATE_INCDIR += $(PKGDIR)/panel/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-lcd-headers libdevice-panel-server + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/letux400/panel-letux400.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/letux400/panel-letux400.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,61 @@ +/* + * Export a panel structure. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include "panel-server.h" + +#include + +static struct Jz4740_lcd_panel panel = { + .config = ( + Jz4740_lcd_mode_tft_generic + | Jz4740_lcd_pclock_negative + | Jz4740_lcd_hsync_negative + | Jz4740_lcd_vsync_negative + | Jz4740_lcd_de_positive), + + .width = 800, + .height = 480, + .bpp = 16, + .frame_rate = 60, + .hsync = 80, + .vsync = 20, + .line_start = 0, + .line_end = 0, + .frame_start = 0, + .frame_end = 0, +}; + +static L4Re::Util::Registry_server<> server; + +int main(void) +{ + /* Initialise and register a new server object. */ + + Panel_server server_obj(&panel, sizeof(panel)); + server.registry()->register_obj(&server_obj, "panel"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/qi_lb60/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/qi_lb60/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_panel_qi_lb60 +PC_FILENAME := devices-panel-qi_lb60 + +SRC_CC := panel-qi_lb60.cc + +PRIVATE_INCDIR += $(PKGDIR)/panel/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-lcd-headers libdevice-panel-server + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/qi_lb60/panel-qi_lb60.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/qi_lb60/panel-qi_lb60.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,61 @@ +/* + * Export a panel structure. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include "panel-server.h" + +#include + +static struct Jz4740_lcd_panel panel = { + .config = ( + Jz4740_lcd_mode_tft_serial + | Jz4740_lcd_pclock_negative + | Jz4740_lcd_hsync_negative + | Jz4740_lcd_vsync_negative + | Jz4740_lcd_de_positive), + + .width = 320, + .height = 240, + .bpp = 32, + .frame_rate = 70, + .hsync = 1, + .vsync = 1, + .line_start = 140, + .line_end = 273, + .frame_start = 20, + .frame_end = 1, +}; + +static L4Re::Util::Registry_server<> server; + +int main(void) +{ + /* Initialise and register a new server object. */ + + Panel_server server_obj(&panel, sizeof(panel)); + server.registry()->register_obj(&server_obj, "panel"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/server/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/server/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_panel_server.o.a +PC_FILENAME := libdevice-panel-server + +SRC_CC := panel-server.cc + +PRIVATE_INCDIR += $(PKGDIR)/panel/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/panel/src/server/panel-server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/panel/src/server/panel-server.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,53 @@ +/* + * Common panel server functionality. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "panel-client.h" +#include "panel-server.h" +#include "panel-ops.h" + +#include +#include +#include +#include + +/* Handle invocations. */ + +int +Panel_server::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) +{ + l4_msgtag_t tag; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case L4::Meta::Protocol: + return L4::Util::handle_meta_request(ios); + + case Panel_op_get_panel: + ios << L4::Ipc::buf_cp_out((uint8_t *) _panel, _size); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/include/pwm-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/include/pwm-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,43 @@ +/* + * PWM client to access PWM servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include "pwm-ops.h" + +/* PWM device interface. */ + +class Pwm_device_interface : public L4::Kobject_t +{ + L4_KOBJECT(Pwm_device_interface) + +public: + int disable() throw(); + int enable() throw(); + int set_control(int control) throw(); + int set_duty(int duty) throw(); + int set_period(int period) throw(); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/include/pwm-ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/include/pwm-ops.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,24 @@ +/* + * PWM server operations. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum { Pwm_op_disable, Pwm_op_enable, Pwm_op_set_control, Pwm_op_set_duty, Pwm_op_set_period }; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := client jz4730 + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/src/client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/src/client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_pwm_client.o.a +PC_FILENAME := libdevice-pwm-client + +SRC_CC := pwm-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/pwm/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/src/client/pwm-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/src/client/pwm-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,70 @@ +/* + * PWM client library to access PWM servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "pwm-client.h" + +/* PWM device interface. */ + +int +Pwm_device_interface::disable() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Pwm_op_disable)); +} + +int +Pwm_device_interface::enable() throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + return l4_error(s.call(cap(), Pwm_op_enable)); +} + +int +Pwm_device_interface::set_control(int control) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + s << control; + return l4_error(s.call(cap(), Pwm_op_set_control)); +} + +int +Pwm_device_interface::set_duty(int duty) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + s << duty; + return l4_error(s.call(cap(), Pwm_op_set_duty)); +} + +int +Pwm_device_interface::set_period(int period) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + s << period; + return l4_error(s.call(cap(), Pwm_op_set_period)); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/src/jz4730/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/src/jz4730/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_pwm_jz4730 +PC_FILENAME := devices-pwm-jz4730 + +SRC_CC := pwm-jz4730.cc + +PRIVATE_INCDIR += $(PKGDIR)/pwm/include $(PKGDIR)/util/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-util libdrivers-pwm libdrivers-gpio # to use GPIO device + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/pwm/src/jz4730/pwm-jz4730.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/pwm/src/jz4730/pwm-jz4730.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,202 @@ +/* + * Export a JZ4730 PWM peripheral as a server. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "pwm-ops.h" +#include "memory.h" + +/* Virtual addresses for the GPIO and PWM register blocks. */ + +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; +static l4_addr_t pwm_virt_base = 0, pwm_virt_base_end = 0; + + + +static int setup_memory(void) +{ + if (get_memory("jz4730-gpio", &gpio_virt_base, &gpio_virt_base_end)) + return 1; + + if (get_memory("jz4730-pwm", &pwm_virt_base, &pwm_virt_base_end)) + return 1; + + return 0; +} + + + +/* PWM peripheral device. */ + +class Pwm_device_server : public L4::Server_object_t +{ + Pwm_jz4730_chip *_device = 0; + int _duty, _period, _prescale; + +public: + /* Associate the device with a particular memory region. */ + + explicit Pwm_device_server(Pwm_jz4730_chip *device, int duty, int period, int prescale) + : _device(device), _duty(duty), _period(period), _prescale(prescale) + { + } + + /* Dispatch incoming requests. */ + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) + { + l4_msgtag_t tag; + int arg; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case Pwm_op_disable: + disable(); + return L4_EOK; + + case Pwm_op_enable: + enable(); + return L4_EOK; + + case Pwm_op_set_control: + ios >> arg; + set_control(arg); + return L4_EOK; + + case Pwm_op_set_duty: + ios >> arg; + set_duty(arg); + return L4_EOK; + + case Pwm_op_set_period: + ios >> arg; + set_period(arg); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } + } + + void disable() + { + _device->disable(); + } + + void enable() + { + set_duty(_duty); + set_period(_period); + set_control(0x80 | _prescale); /* enable | prescale */ + } + + /* Set the control register. */ + + void set_control(uint8_t control) + { + _device->set_control(control); + } + + /* Set the PWM duty cycle. */ + + void set_duty(uint16_t duty) + { + _duty = duty; + _device->set_duty(duty); + } + + /* Set the PWM period. */ + + void set_period(uint16_t period) + { + _period = period; + _device->set_period(period); + } +}; + +static L4Re::Util::Registry_server<> server; + + + +/* Initialise devices and start the server. */ + +static void run(int number, int duty, int period, int prescale) +{ + Pwm_jz4730_chip pwm_device(pwm_virt_base + number * 0x1000, + pwm_virt_base + (number + 1) * 0x1000); + + Gpio_jz4730_chip gpio_port_c(gpio_virt_base + 2 * 0x30, + gpio_virt_base + 3 * 0x30, 32); + + /* Enable the PWM output for PC30 or PC31. */ + + gpio_port_c.config_pad(30 + number, Hw::Gpio_chip::Function_alt, 1); + + /* Initialise and register a new server object. */ + + Pwm_device_server server_obj(&pwm_device, duty, period, prescale); + server.registry()->register_obj(&server_obj, "pwm"); + + /* Enter the IPC server loop. */ + + server.loop(); +} + + + +/* Arguments: */ + +int main(int argc, char *argv[]) +{ + int number, duty, period, prescale; + + if (argc < 5) return 1; + + /* Interpret and restrict the device number. */ + + number = atoi(argv[1]); + if ((number < 0) || (number > 1)) return 1; + + /* Interpret and restrict the initial parameters. */ + + duty = atoi(argv[2]); + period = atoi(argv[3]); + prescale = atoi(argv[4]); + if ((duty < 0) || (period < 0) || (prescale < 0)) return 1; + + /* Obtain access to peripheral memory. */ + + if (setup_memory()) return 1; + + run(number, duty, period, prescale); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/include/spi-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/include/spi-client.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,39 @@ +/* + * SPI client to access SPI servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#ifdef __cplusplus + +#include +#include "spi-ops.h" + +/* SPI device interface. */ + +class Spi_device_interface : public L4::Kobject_t +{ + L4_KOBJECT(Spi_device_interface) + +public: + int send(int bits, int data) throw(); +}; + +#endif diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/include/spi-ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/include/spi-ops.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,24 @@ +/* + * SPI server operations. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +enum { Spi_op_send }; diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := client jz4740 + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/src/client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/src/client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_spi_client.o.a +PC_FILENAME := libdevice-spi-client + +SRC_CC := spi-client.cc + +PRIVATE_INCDIR += $(PKGDIR)/spi/include + +REQUIRES_LIBS := l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/src/client/spi-client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/src/client/spi-client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,36 @@ +/* + * SPI client library to access SPI servers. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "spi-client.h" + +/* SPI device interface. */ + +int +Spi_device_interface::send(int bits, int data) throw() +{ + L4::Ipc::Iostream s(l4_utcb()); + + s << bits << data; + return l4_error(s.call(cap(), Spi_op_send)); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/src/jz4740/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/src/jz4740/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dev_spi_jz4740 +PC_FILENAME := devices-spi-jz4740 + +SRC_CC := spi-jz4740.cc + +PRIVATE_INCDIR += $(PKGDIR)/spi/include $(PKGDIR)/util/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdevice-util libdrivers-gpio # to use GPIO device + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/spi/src/jz4740/spi-jz4740.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/spi/src/jz4740/spi-jz4740.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,212 @@ +/* + * Export JZ4740 GPIO pins as a SPI server. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "spi-ops.h" +#include "memory.h" + +/* Virtual addresses for the GPIO register block. */ + +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; + + + +static int setup_memory(void) +{ + if (get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end)) + return 1; + + return 0; +} + + + +/* SPI peripheral device. */ + +class Spi_device_server : public L4::Server_object_t +{ + Gpio_jz4740_chip *_clock_device = 0, *_data_device = 0, *_enable_device = 0; + int _clock_pin, _data_pin, _enable_pin; + +public: + /* Associate the device with a particular memory region. */ + + explicit Spi_device_server(Gpio_jz4740_chip *clock_device, + Gpio_jz4740_chip *data_device, + Gpio_jz4740_chip *enable_device, + int clock_pin, int data_pin, int enable_pin) + : _clock_device(clock_device), + _data_device(data_device), + _enable_device(enable_device), + _clock_pin(clock_pin), _data_pin(data_pin), _enable_pin(enable_pin) + { + } + + /* Dispatch incoming requests. */ + + int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) + { + l4_msgtag_t tag; + int bits, data; + + (void) obj; + ios >> tag; + + switch (tag.label()) + { + case Spi_op_send: + ios >> bits; + ios >> data; + send(bits, data); + return L4_EOK; + + default: + return -L4_EBADPROTO; + } + } + + /* Send a SPI command. */ + + void send(int bits, int data) + { + uint32_t mask = 1 << (bits - 1); + int bit; + + /* Initialise pin levels. */ + + _enable_device->set(_enable_pin, 1); + _clock_device->set(_clock_pin, 1); + _data_device->set(_data_pin, 0); + + /* Enter the transmission state. */ + + _enable_device->set(_enable_pin, 0); + + /* Clock data using the clock and data outputs. */ + + for (bit = 0; bit < bits; bit++) + { + _clock_device->set(_clock_pin, 0); + _data_device->set(_data_pin, data & mask ? 1 : 0); + _clock_device->set(_clock_pin, 1); + mask >>= 1; + } + + _enable_device->set(_enable_pin, 1); + } +}; + +static L4Re::Util::Registry_server<> server; + + + +/* +Parse a string of the form "" where is a single character +whose position in the ports string indicates the port number, and where is +either a base 10 number, a base 8 number preceded by "0", or a base 16 number +preceded by "0x" or "0X", defined by the strtol library function. +*/ + +static int parse_pin(const char *s, const char *ports, int *port, int *pin) +{ + int i = 0; + + if (!s || !(*s)) return 0; + + /* Parse prefix in character range. */ + + while (*ports) + { + if (s[0] == *ports) + { + *port = i; + + /* Parse pin number. */ + + *pin = (int) strtol(s+1, NULL, 0); + return !errno; + } + ports++; i++; + } + + return 0; +} + +/* Arguments: */ + +int main(int argc, char *argv[]) +{ + int clock_port, clock_pin, data_port, data_pin, enable_port, enable_pin; + + if (argc < 4) return 1; + + /* Interpret the pin details. */ + + if (!parse_pin(argv[1], "ABCD", &clock_port, &clock_pin)) return 1; + if (!parse_pin(argv[2], "ABCD", &data_port, &data_pin)) return 1; + if (!parse_pin(argv[3], "ABCD", &enable_port, &enable_pin)) return 1; + + /* Obtain access to peripheral memory. */ + + if (setup_memory()) return 1; + + /* Configure the clock pin. */ + + Gpio_jz4740_chip gpio_port_clock(gpio_virt_base + clock_port * 0x100, + gpio_virt_base + (clock_port + 1) * 0x100, 32); + + gpio_port_clock.setup(clock_pin, Hw::Gpio_chip::Output, 0); + + /* Configure the data pin. */ + + Gpio_jz4740_chip gpio_port_data(gpio_virt_base + data_port * 0x100, + gpio_virt_base + (data_port + 1) * 0x100, 32); + + gpio_port_data.setup(data_pin, Hw::Gpio_chip::Output, 0); + + /* Configure the enable pin. */ + + Gpio_jz4740_chip gpio_port_enable(gpio_virt_base + enable_port * 0x100, + gpio_virt_base + (enable_port + 1) * 0x100, 32); + + gpio_port_enable.setup(enable_pin, Hw::Gpio_chip::Output, 0); + + /* Initialise and register a new server object. */ + + Spi_device_server server_obj(&gpio_port_clock, &gpio_port_data, &gpio_port_enable, + clock_pin, data_pin, enable_pin); + + server.registry()->register_obj(&server_obj, "spi"); + + /* Enter the IPC server loop. */ + + server.loop(); + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/util/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/util/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/include/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,4 @@ +PKGDIR = ../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/util/include/dataspace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/include/dataspace.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,28 @@ +/* + * Data space allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include + +L4::Cap allocate_data(l4_size_t mem_size, void **allocated); diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/util/include/memory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/include/memory.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,34 @@ +/* + * Memory allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include + +int get_device(char const *hid, l4io_device_handle_t *dh, + l4io_resource_handle_t *rh); + +int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type); + +int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end); diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/util/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/src/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,13 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libdevice_util.o.a +PC_FILENAME := libdevice-util + +SRC_CC := dataspace.cc memory.cc + +PRIVATE_INCDIR += $(PKGDIR)/util/include + +REQUIRES_LIBS := libio l4re_c l4re_c-util + +include $(L4DIR)/mk/lib.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/util/src/dataspace.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/src/dataspace.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,63 @@ +/* + * Data space allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "dataspace.h" + +/* +Allocate and map a region containing data, using the given mem_size to indicate +the required region size, along with a pointer to be set to the allocated +region. Return a capability which may be invalid if allocation or mapping +failed. +*/ + +L4::Cap allocate_data(l4_size_t mem_size, void **allocated) +{ + /* Obtain a capability for the allocated memory. */ + + L4::Cap mem = L4Re::Util::cap_alloc.alloc(); + + if (!mem.is_valid()) + return L4::Cap::Invalid; + + /* Allocate memory for the data. */ + + if (L4Re::Env::env()->mem_alloc()->alloc(mem_size, mem, L4Re::Mem_alloc::Continuous)) + { + L4Re::Util::cap_alloc.free(mem); + return L4::Cap::Invalid; + } + + /* Map the memory to a virtual address. */ + + if (L4Re::Env::env()->rm()->attach(allocated, mem->size(), L4Re::Rm::Search_addr, + L4::Ipc::make_cap_rw(mem))) + { + L4Re::Util::cap_alloc.free(mem); + return L4::Cap::Invalid; + } + + return mem; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/devices/util/src/memory.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/util/src/memory.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,78 @@ +/* + * Memory allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include + +#include "memory.h" + +int get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) +{ + return l4io_lookup_device(hid, dh, 0, rh); +} + +int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type) +{ + int current = 0, result = 0; + l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); + + do + { + result = l4vbus_get_resource(vbus, dh, current, res); + current++; + } + while ((!result) && (res->type != type)); + + return result; +} + +int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = get_resource(dh, &res, L4IO_RESOURCE_MEM); + + if (result) + return result; + + result = l4io_request_iomem(res.start, res.end - res.start + 1, + L4IO_MEM_NONCACHED, start); + + if (result) + return result; + + *end = *start + (res.end - res.start + 1); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,6 @@ +PKGDIR = .. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = $(wildcard [a-z]*) + +include $(L4DIR)/mk/subdir.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/ci20_cpm/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/ci20_cpm/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_ci20_cpm +SRC_C = ci20_cpm.c +REQUIRES_LIBS = libio l4re_c-util libdrivers-cpm + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/ci20_cpm/ci20_cpm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/ci20_cpm/ci20_cpm.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,197 @@ +/* + * (c) 2008-2009 Adam Lackorzynski + * economic rights: Technische Universität Dresden (Germany) + * (c) 2017, 2018 Paul Boddie + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ +/* + * Access the clock and power management unit on the MIPS Creator CI20 board. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/* Device and resource discovery. */ + +static char const *resource_type(enum l4io_resource_types_t type) +{ + switch (type) + { + case L4VBUS_RESOURCE_INVALID: + return "INVALID"; + + case L4VBUS_RESOURCE_IRQ: + return "IRQ"; + + case L4VBUS_RESOURCE_MEM: + return "MEMORY"; + + default: + return "OTHER"; + } +} + +static int cpm_get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) +{ + int result = l4io_lookup_device(hid, dh, 0, rh); + + if (result < 0) + printf("Could not access '%s': %s\n", hid, result == -L4_ENOENT ? "no such device" : "no device"); + + return result; +} + +static int cpm_get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type) +{ + int current = 0, result = 0; + l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); + + do + { + result = l4vbus_get_resource(vbus, dh, current, res); + + if (result) + printf("Could not access resource of type %s.\n", resource_type(type)); + else + printf("Resource %d: type %s, start=%lx, end=%lx\n", res->id, + resource_type(res->type), res->start, res->end); + + current++; + } + while ((!result) && (res->type != type)); + + return result; +} + +static int cpm_get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = cpm_get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = cpm_get_resource(dh, &res, L4IO_RESOURCE_MEM); + + if (result) + return result; + + if ((result = l4io_request_iomem(res.start, res.end - res.start + 1, + L4IO_MEM_NONCACHED, start))) + { + printf("Could not get address for '%s'.\n", hid); + return result; + } + + printf("Resource at 0x%lx...0x%lx.\n", res.start, res.end); + + *end = *start + (res.end - res.start + 1); + + return 0; +} + +int main(void) +{ + l4_addr_t cpm_base = 0, cpm_base_end = 0; + void *cpm; + int result = 0; + + /* Obtain resource details describing I/O memory. */ + + printf("Access CPM...\n"); + + if ((result = cpm_get_memory("jz4780-cpm", &cpm_base, &cpm_base_end)) < 0) + return 1; + + printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end); + + cpm = jz4780_cpm_init(cpm_base); + + /* Read information from the clock and power management unit. */ + + printf("Main source: %d\n", jz4780_cpm_get_main_source(cpm)); + printf(" Main frequency: %d\n", jz4780_cpm_get_main_frequency(cpm)); + printf("APLL frequency: %d\n", jz4780_cpm_get_apll_frequency(cpm)); + printf("EPLL frequency: %d\n", jz4780_cpm_get_epll_frequency(cpm)); + printf("MPLL frequency: %d\n", jz4780_cpm_get_mpll_frequency(cpm)); + printf("VPLL frequency: %d\n", jz4780_cpm_get_vpll_frequency(cpm)); + printf("CPU divider: %d\n", jz4780_cpm_get_cpu_divider(cpm)); + printf(" CPU frequency: %d\n", jz4780_cpm_get_cpu_frequency(cpm)); + printf("Memory source: %d\n", jz4780_cpm_get_memory_source(cpm)); + printf(" Memory source frequency: %d\n", jz4780_cpm_get_memory_source_frequency(cpm)); + printf(" Memory divider: %d\n", jz4780_cpm_get_memory_divider(cpm)); + printf(" Memory frequency: %d\n", jz4780_cpm_get_memory_frequency(cpm)); + printf("APB source: %d\n", jz4780_cpm_get_pclock_source(cpm)); + printf(" APB source frequency: %d\n", jz4780_cpm_get_pclock_source_frequency(cpm)); + printf(" APB divider: %d\n", jz4780_cpm_get_pclock_divider(cpm)); + printf(" Slow peripheral (APB) frequency: %d\n", jz4780_cpm_get_pclock_frequency(cpm)); + printf("AHB0 source: %d\n", jz4780_cpm_get_hclock0_source(cpm)); + printf(" AHB0 source frequency: %d\n", jz4780_cpm_get_hclock0_source_frequency(cpm)); + printf(" AHB0 divider: %d\n", jz4780_cpm_get_hclock0_divider(cpm)); + printf(" Fast peripheral (AHB0) frequency: %d\n", jz4780_cpm_get_hclock0_frequency(cpm)); + printf("AHB2 source: %d\n", jz4780_cpm_get_hclock2_source(cpm)); + printf(" AHB2 source frequency: %d\n", jz4780_cpm_get_hclock2_source_frequency(cpm)); + printf(" AHB2 divider: %d\n", jz4780_cpm_get_hclock2_divider(cpm)); + printf(" Fast peripheral (AHB2) frequency: %d\n", jz4780_cpm_get_hclock2_frequency(cpm)); + printf("LCD source: %d\n", jz4780_cpm_get_lcd_source(cpm)); + printf(" LCD source frequency: %d\n", jz4780_cpm_get_lcd_source_frequency(cpm)); + printf(" LCD pixel clock divider: %d\n", jz4780_cpm_get_lcd_pixel_divider(cpm)); + printf(" LCD pixel clock frequency: %d\n", jz4780_cpm_get_lcd_pixel_frequency(cpm)); + + /* Attempt to set the pixel clock frequency. */ + + jz4780_cpm_set_lcd_pixel_frequency(cpm, 108000000); + + printf("LCD source: %d\n", jz4780_cpm_get_lcd_source(cpm)); + printf(" LCD source frequency: %d\n", jz4780_cpm_get_lcd_source_frequency(cpm)); + printf(" LCD pixel clock divider: %d\n", jz4780_cpm_get_lcd_pixel_divider(cpm)); + printf(" LCD pixel clock frequency: %d\n", jz4780_cpm_get_lcd_pixel_frequency(cpm)); + + /* Attempt to set the peripheral clock frequency. */ + + jz4780_cpm_set_pclock_source(cpm, 1); + + printf("APB source: %d\n", jz4780_cpm_get_pclock_source(cpm)); + printf(" APB source frequency: %d\n", jz4780_cpm_get_pclock_source_frequency(cpm)); + printf(" APB divider: %d\n", jz4780_cpm_get_pclock_divider(cpm)); + printf(" Slow peripheral (APB) frequency: %d\n", jz4780_cpm_get_pclock_frequency(cpm)); + printf("AHB2 source: %d\n", jz4780_cpm_get_hclock2_source(cpm)); + printf(" AHB2 source frequency: %d\n", jz4780_cpm_get_hclock2_source_frequency(cpm)); + printf(" AHB2 divider: %d\n", jz4780_cpm_get_hclock2_divider(cpm)); + printf(" Fast peripheral (AHB2) frequency: %d\n", jz4780_cpm_get_hclock2_frequency(cpm)); + + /* Attempt to set the MPLL output to EXCLK divided by 4. */ + + jz4780_cpm_set_mpll_parameters(cpm, 1, 4, 1); + + printf("APB source: %d\n", jz4780_cpm_get_pclock_source(cpm)); + printf(" APB source frequency: %d\n", jz4780_cpm_get_pclock_source_frequency(cpm)); + printf(" APB divider: %d\n", jz4780_cpm_get_pclock_divider(cpm)); + printf(" Slow peripheral (APB) frequency: %d\n", jz4780_cpm_get_pclock_frequency(cpm)); + printf("AHB2 source: %d\n", jz4780_cpm_get_hclock2_source(cpm)); + printf(" AHB2 source frequency: %d\n", jz4780_cpm_get_hclock2_source_frequency(cpm)); + printf(" AHB2 divider: %d\n", jz4780_cpm_get_hclock2_divider(cpm)); + printf(" Fast peripheral (AHB2) frequency: %d\n", jz4780_cpm_get_hclock2_frequency(cpm)); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/ci20_i2c/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/ci20_i2c/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_ci20_i2c +SRC_C = ci20_i2c.c +REQUIRES_LIBS = libio l4re_c-util libdrivers-i2c libdrivers-cpm libdrivers-gpio libedid + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/ci20_i2c/ci20_i2c.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,348 @@ +/* + * (c) 2008-2009 Adam Lackorzynski + * economic rights: Technische Universität Dresden (Germany) + * (c) 2017, 2018 Paul Boddie + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ +/* + * Access the I2C peripherals on the MIPS Creator CI20 board. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +enum { + DDCSCL = 24, /* via PORTF */ + DDCSDA = 25, /* via PORTF */ +}; + + + +/* Device and resource discovery. */ + +static char const *resource_type(enum l4io_resource_types_t type) +{ + switch (type) + { + case L4VBUS_RESOURCE_INVALID: + return "INVALID"; + + case L4VBUS_RESOURCE_IRQ: + return "IRQ"; + + case L4VBUS_RESOURCE_MEM: + return "MEMORY"; + + default: + return "OTHER"; + } +} + +static int vbus_get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) +{ + int result = l4io_lookup_device(hid, dh, 0, rh); + + if (result < 0) + printf("Could not access '%s': %s\n", hid, result == -L4_ENOENT ? "no such device" : "no device"); + + return result; +} + +static int vbus_get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type) +{ + int current = 0, result = 0; + l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); + + do + { + result = l4vbus_get_resource(vbus, dh, current, res); + + if (result) + printf("Could not access resource of type %s.\n", resource_type(type)); + else + printf("Resource %d: type %s, start=%lx, end=%lx\n", res->id, + resource_type(res->type), res->start, res->end); + + current++; + } + while ((!result) && (res->type != type)); + + return result; +} + +static int vbus_get_irq(char const *hid, l4_uint32_t *start, l4_uint32_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = vbus_get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = vbus_get_resource(dh, &res, L4IO_RESOURCE_IRQ); + + if (result) + return result; + + *start = res.start; + *end = res.end; + + return result; +} + +static int vbus_get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = vbus_get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = vbus_get_resource(dh, &res, L4IO_RESOURCE_MEM); + + if (result) + return result; + + if ((result = l4io_request_iomem(res.start, res.end - res.start + 1, + L4IO_MEM_NONCACHED, start))) + { + printf("Could not get address for '%s'.\n", hid); + return result; + } + + printf("Resource at 0x%lx...0x%lx.\n", res.start, res.end); + + *end = *start + (res.end - res.start + 1); + + return 0; +} + +static long item_in_range(long start, long end, long index) +{ + if (start < end) + return start + index; + else + return start - index; +} + +static void show_deviceid(uint8_t buf[]) +{ + printf("Manufacturer %x part %x revision %x\n", + (buf[0] << 4) | (buf[1] >> 4), + ((buf[1] & 0xf) << 5) | (buf[2] >> 3), + buf[2] & 0x7); +} + +static void show_data(uint8_t buf[], unsigned pos) +{ + unsigned i; + + if (pos) + { + printf("Read %d bytes from bus.\n", pos); + for (i = 0; i < pos; i++) + printf(" %02x", buf[i]); + printf("\n"); + } + else + printf("No reply from bus.\n"); +} + +int main(void) +{ + l4_addr_t gpio_base = 0, gpio_base_end = 0; + l4_addr_t port_f, port_f_end; + l4_addr_t i2c_base = 0, i2c_base_end = 0, cpm_base = 0, cpm_base_end; + void *gpio_port_f; + void *i2c, *i2c_channel, *cpm; + l4_uint32_t i2c_irq_start = 0, i2c_irq_end = 0, i2c_irq; + l4_cap_idx_t irqcap, icucap; + l4_msgtag_t tag; + long err; + int result = 0; + uint8_t buf[256]; + unsigned pos; + unsigned width = 0, height = 0; + + /* Obtain capabilities for the interrupt controller and an interrupt. */ + + irqcap = l4re_util_cap_alloc(); + icucap = l4re_env_get_cap("icu"); + + if (l4_is_invalid_cap(icucap)) + { + printf("No 'icu' capability available in the virtual bus.\n"); + return 1; + } + + if (l4_is_invalid_cap(irqcap)) + { + printf("No capability available for the interrupt.\n"); + return 1; + } + + /* Obtain resource details describing the interrupt for I2C channel 4. */ + + printf("Access IRQ...\n"); + + if ((result = vbus_get_irq("jz4780-i2c", &i2c_irq_start, &i2c_irq_end)) < 0) + return 1; + + i2c_irq = item_in_range(i2c_irq_start, i2c_irq_end, 4); + printf("IRQ range at %d...%d.\n", i2c_irq_start, i2c_irq_end); + printf("I2C IRQ at %d.\n", i2c_irq); + + /* Obtain resource details describing I/O memory. */ + + printf("Access GPIO...\n"); + + if ((result = vbus_get_memory("jz4780-gpio", &gpio_base, &gpio_base_end)) < 0) + return 1; + + printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end); + + printf("Access CPM...\n"); + + if ((result = vbus_get_memory("jz4780-cpm", &cpm_base, &cpm_base_end)) < 0) + return 1; + + printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end); + + printf("Access I2C...\n"); + + if ((result = vbus_get_memory("jz4780-i2c", &i2c_base, &i2c_base_end)) < 0) + return 1; + + printf("I2C at 0x%lx...0x%lx.\n", i2c_base, i2c_base_end); + + /* Create an interrupt object. */ + + if ((err = l4_error(tag = l4_factory_create_irq(l4re_global_env->factory, irqcap)))) + { + printf("Could not create IRQ object: %lx\n", err); + return 1; + } + + /* Bind the interrupt object to the IRQ number. */ + + if ((err = l4_error(l4_icu_bind(icucap, i2c_irq, irqcap)))) + { + printf("Could not bind IRQ %d to the ICU: %ld\n", i2c_irq, err); + return 1; + } + + /* Attach ourselves to the interrupt handler. */ + + tag = l4_irq_attach(irqcap, 0xDEAD, l4re_env()->main_thread); + + if ((err = l4_error(tag))) + { + printf("Could not attach to IRQ %d: %ld\n", i2c_irq, err); + return 1; + } + + /* Configure pins. */ + + port_f = gpio_base + 0x500; + port_f_end = port_f + 0x100; + + printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end); + + gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0xffa7f00f, 0x00580ff0); + + printf("Set up GPIO pins...\n"); + + jz4780_gpio_config_pad(gpio_port_f, DDCSCL, Function_alt, 1); + jz4780_gpio_config_pad(gpio_port_f, DDCSDA, Function_alt, 1); + + /* Obtain CPM and I2C objects. */ + + cpm = jz4780_cpm_init(cpm_base); + + /* Attempt to set the PCLK source to SCLK_A. */ + + jz4780_cpm_set_pclock_source(cpm, 1); + printf("Peripheral clock: %d\n", jz4780_cpm_get_pclock_frequency(cpm)); + + /* Obtain I2C reference. */ + + i2c = jz4780_i2c_init(i2c_base, i2c_base_end, cpm, 100000); /* 100 kHz */ + + printf("Trying DDC on I2C4...\n"); + + i2c_channel = jz4780_i2c_get_channel(i2c, 4); + + /* Attempt to read from address 0x50 for DDC. + See: drivers/video/fbdev/core/fb_ddc.c */ + + jz4780_i2c_set_target(i2c_channel, 0x50); + buf[0] = 0; + jz4780_i2c_write(i2c_channel, buf, 1); + jz4780_i2c_start_read(i2c_channel, buf, 128); + + printf("Waiting\n"); + + while (!jz4780_i2c_read_done(i2c_channel)) + { + if (jz4780_i2c_read_incomplete(i2c_channel)) + { + printf("Failed\n"); + break; + } + + tag = l4_irq_receive(irqcap, L4_IPC_NEVER); + + if ((err = l4_ipc_error(tag, l4_utcb()))) + { + printf("Error on IRQ receive: %ld\n", err); + continue; + } + + jz4780_i2c_read(i2c_channel); + } + + pos = jz4780_i2c_have_read(i2c_channel); + show_data(buf, pos); + + /* Attempt to decode EDID information. */ + + libedid_prefered_resolution(buf, &width, &height); + printf("Preferred resolution: %d x %d\n", width, height); + + libedid_dump_standard_timings(buf); + + /* Detach from the interrupt. */ + + tag = l4_irq_detach(irqcap); + + if ((err = l4_error(tag))) + printf("Error detaching from IRQ: %ld\n", err); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/ci20_leds/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/ci20_leds/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_ci20_leds +SRC_C = ci20_leds.c +REQUIRES_LIBS = libio l4re_c-util libdrivers-gpio + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/ci20_leds/ci20_leds.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/ci20_leds/ci20_leds.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,275 @@ +/* + * (c) 2008-2009 Adam Lackorzynski + * economic rights: Technische Universität Dresden (Germany) + * (c) 2017, 2018 Paul Boddie + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ +/* + * Access the LED and other GPIOs on the MIPS Creator CI20 board. + * This example shows how to use the following GPIOs: + * + * PD17 - SW1 button + * PF15 - blue/red LED (high -> red, low -> blue) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + LED = 15, // via PORTF + SW1 = 17, // via PORTD +}; + + + +/* Device and resource discovery. */ + +static char const *resource_type(enum l4io_resource_types_t type) +{ + switch (type) + { + case L4VBUS_RESOURCE_INVALID: + return "INVALID"; + + case L4VBUS_RESOURCE_IRQ: + return "IRQ"; + + case L4VBUS_RESOURCE_MEM: + return "MEMORY"; + + default: + return "OTHER"; + } +} + +static int gpio_get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) +{ + int result = l4io_lookup_device(hid, dh, 0, rh); + + if (result < 0) + printf("Could not access '%s': %s\n", hid, result == -L4_ENOENT ? "no such device" : "no device"); + + return result; +} + +static int gpio_get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type) +{ + int current = 0, result = 0; + l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); + + do + { + result = l4vbus_get_resource(vbus, dh, current, res); + + if (result) + printf("Could not access resource of type %s.\n", resource_type(type)); + else + printf("Resource %d: type %s, start=%lx, end=%lx\n", res->id, + resource_type(res->type), res->start, res->end); + + current++; + } + while ((!result) && (res->type != type)); + + return result; +} + +static int gpio_get_irq(char const *hid, l4_uint32_t *start, l4_uint32_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = gpio_get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = gpio_get_resource(dh, &res, L4IO_RESOURCE_IRQ); + + if (result) + return result; + + *start = res.start; + *end = res.end; + + return result; +} + +static int gpio_get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = gpio_get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = gpio_get_resource(dh, &res, L4IO_RESOURCE_MEM); + + if (result) + return result; + + if ((result = l4io_request_iomem(res.start, res.end - res.start + 1, + L4IO_MEM_NONCACHED, start))) + { + printf("Could not get address for '%s'.\n", hid); + return result; + } + + printf("Resource at 0x%lx...0x%lx.\n", res.start, res.end); + + *end = *start + (res.end - res.start + 1); + + return 0; +} + +static long item_in_range(long start, long end, long index) +{ + if (start < end) + return start + index; + else + return start - index; +} + +int main(void) +{ + l4_addr_t gpio_base = 0, gpio_base_end = 0, port_d, port_d_end, port_f, port_f_end; + l4_uint32_t gpio_irq_start = 0, gpio_irq_end = 0, gpio_irq; + l4_cap_idx_t irqcap, icucap; + l4_msgtag_t tag; + long err; + void *gpio_port_d, *gpio_port_f, *gpio_irq_pin; + int result = 0; + int led = 0; + + /* Obtain capabilities for the interrupt controller and an interrupt. */ + + irqcap = l4re_util_cap_alloc(); + icucap = l4re_env_get_cap("icu"); + + if (l4_is_invalid_cap(icucap)) + { + printf("No 'icu' capability available in the virtual bus.\n"); + return 1; + } + + if (l4_is_invalid_cap(irqcap)) + { + printf("No capability available for the interrupt.\n"); + return 1; + } + + /* Obtain resource details describing the interrupt and I/O memory. */ + + printf("Access IRQ...\n"); + + if ((result = gpio_get_irq("jz4780-gpio", &gpio_irq_start, &gpio_irq_end)) < 0) + return 1; + + gpio_irq = item_in_range(gpio_irq_start, gpio_irq_end, 3); + printf("IRQ range at %d...%d.\n", gpio_irq_start, gpio_irq_end); + printf("PORTD IRQ at %d.\n", gpio_irq); + + printf("Access GPIO...\n"); + + if ((result = gpio_get_memory("jz4780-gpio", &gpio_base, &gpio_base_end)) < 0) + return 1; + + port_d = gpio_base + 0x300; + port_d_end = port_d + 0x100; + port_f = gpio_base + 0x500; + port_f_end = port_f + 0x100; + + printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end); + printf("PORTD at 0x%lx...0x%lx.\n", port_d, port_d_end); + printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end); + + gpio_port_d = jz4780_gpio_init(port_d, port_d_end, 32, 0xffff4fff, 0x0000b000); + gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0xffa7f00f, 0x00580ff0); + + /* Create an interrupt object. */ + + if ((err = l4_error(tag = l4_factory_create_irq(l4re_global_env->factory, irqcap)))) + { + printf("Could not create IRQ object: %lx\n", err); + return 1; + } + + /* Bind the interrupt object to the IRQ number. */ + + if ((err = l4_error(l4_icu_bind(icucap, gpio_irq, irqcap)))) + { + printf("Could not bind IRQ %d to the ICU: %ld\n", gpio_irq, err); + return 1; + } + + /* Attach ourselves to the interrupt handler. */ + + tag = l4_irq_attach(irqcap, 0xDEAD, l4re_env()->main_thread); + + if ((err = l4_error(tag))) + { + printf("Could not attach to IRQ %d: %ld\n", gpio_irq, err); + return 1; + } + + /* Set the GPIO pins up. */ + + printf("Set up GPIO pins...\n"); + + jz4780_gpio_setup(gpio_port_d, SW1, L4VBUS_GPIO_SETUP_IRQ, 1); + jz4780_gpio_setup(gpio_port_f, LED, L4VBUS_GPIO_SETUP_OUTPUT, 0); + + gpio_irq_pin = jz4780_gpio_get_irq(gpio_port_d, SW1); + jz4780_gpio_irq_set_mode(gpio_irq_pin, L4_IRQ_F_LEVEL_HIGH); + + printf("Press SW1 to invert LED.\n"); + + while (1) + { + tag = l4_irq_receive(irqcap, L4_IPC_NEVER); + + if ((err = l4_ipc_error(tag, l4_utcb()))) + { + printf("Error on IRQ receive: %ld\n", err); + continue; + } + + printf("SW1: %x\n", jz4780_gpio_get(gpio_port_d, SW1)); + + if (jz4780_gpio_get(gpio_port_d, SW1)) + { + printf("Invert LED\n"); + jz4780_gpio_set(gpio_port_f, LED, led); + led = 1 - led; + } + } + + /* Detach from the interrupt. */ + + tag = l4_irq_detach(irqcap); + + if ((err = l4_error(tag))) + printf("Error detaching from IRQ: %ld\n", err); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/jz4740_lcd_driver/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/jz4740_lcd_driver/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_jz4740_lcd_driver +SRC_C = jz4740_lcd_driver.c +REQUIRES_LIBS = libdevice-lcd-jz4740 + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/jz4740_lcd_driver/jz4740_lcd_driver.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/jz4740_lcd_driver/jz4740_lcd_driver.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,84 @@ +/* + * Access the LCD on JZ4740-based platforms. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include + +int main(void) +{ + l4re_video_view_info_t view_info; + l4_size_t i, limit, line, digit, row, mask, value, onpix, offpix; + + /* Obtain device and get framebuffer details. */ + + void *lcd_device = lcd_get_device(); + l4_addr_t fb_vaddr = lcd_get_framebuffer(lcd_device); + l4_size_t fb_size = lcd_get_framebuffer_size(lcd_device); + uint32_t *fb32 = (uint32_t *) fb_vaddr; + uint16_t *fb16 = (uint16_t *) fb_vaddr; + + if (!fb_vaddr) return 1; + + lcd_get_view_info(lcd_device, &view_info); + lcd_enable(lcd_device); + + /* Try and show some values. */ + + onpix = 0xffaaffaa; offpix = 0x11551155; + mask = 0x80000000; value = (l4_size_t) view_info.width; + + i = 0; + limit = fb_size / view_info.pixel_info.bytes_per_pixel; + line = limit / view_info.height; + digit = line / 32; + row = line * 10; + + while (i < limit) + { + if (view_info.pixel_info.bytes_per_pixel == 2) + fb16[i] = value & mask ? onpix : offpix; + else + fb32[i] = value & mask ? onpix : offpix; + + i++; + + if ((i % digit) == 0) + { + if (mask == 1) mask = 0x80000000; + else mask >>= 1; + + onpix = (onpix >> 8) | ((onpix & 0xff) << 24); + offpix = (offpix >> 8) | ((offpix & 0xff) << 24); + + if (i == row) value = (l4_size_t) view_info.height; + else if (i == (row * 2)) value = 0x80000001; + } + } + + l4_cache_clean_data((unsigned long) fb_vaddr, (unsigned long) fb_vaddr + fb_size); + + while (1); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/keypad_ds_client/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/keypad_ds_client/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,10 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_keypad_ds_client +#SRC_CC = keypad_ds_client.cc +#REQUIRES_LIBS = l4re_c-util libdevice-keypad-client +SRC_C = keypad_ds_client_c.c +REQUIRES_LIBS = l4re_c-util libdevice-keypad-ops + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/keypad_ds_client/keypad_ds_client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/keypad_ds_client/keypad_ds_client.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,170 @@ +/* + * Display the keypad matrix using the specified dimensions. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +/* Video abstractions. */ + +static l4re_util_video_goos_fb_t gfb; +static l4re_video_view_info_t fbi; +static void *fb; + +/* Keypad status and dimensions. */ + +uint32_t *keypad = 0; +void *keymem = 0; +int columns, rows; + + + +static uint32_t bitmask(uint32_t size) +{ + return (1 << size) - 1; +} + +static uint32_t truncate_channel(uint32_t value, uint32_t size) +{ + return (value >> (8 - size)) & bitmask(size); +} + +static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) +{ + if (bpp <= 8) *(uint8_t *) pos = value; + else if (bpp <= 16) *(uint16_t *) pos = value; + else *(uint32_t *) pos = value; +} + +/* Show the state of a key on the display. */ + +static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) +{ + uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); + uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; + uint32_t bytes_per_line = fbi.bytes_per_line; + uint32_t pos; + uint32_t col, row; + + rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | + (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | + (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); + + for (row = 0; row < h; row++) + { + pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; + + for (col = 0; col < w; col++) + { + set_pixel(pos, bpp, rgb); + pos += bytes_per_pixel; + } + } +} + +/* Show the keypad status on the display. */ + +static void show_keypad(void) +{ + uint32_t colsize = fbi.width / columns, + rowsize = fbi.height / rows; + uint8_t column, row; + uint32_t mask; + + for (column = 0; column < columns; column++) + + for (row = 0, mask = 1 << (rows - 1); + row < rows; + row++, mask >>= 1) + + show_keystate(column * colsize, row * rowsize, colsize, rowsize, + keypad[column] & mask ? 0xffffff : 0); + + /* Refresh the display. */ + + l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); +} + + + +int main(int argc, char *argv[]) +{ + L4::Cap keypad_server; + L4::Cap mem; + + /* Obtain the keypad matrix dimensions. */ + + if (argc < 3) + return 1; + + columns = atoi(argv[1]); + rows = atoi(argv[2]); + + if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) + return 1; + + if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) + return 1; + + if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) + return 1; + + /* Obtain a reference to the keypad. */ + + keypad_server = L4Re::Env::env()->get_cap("keypad"); + if (!keypad_server.is_valid()) return 1; + + /* Obtain a capability for the keypad data. */ + + mem = L4Re::Util::cap_alloc.alloc(); + if (!mem.is_valid()) return 1; + + /* Obtain a reference to the keypad data. */ + + if (keypad_server->get_keypad_data(mem)) return 1; + + /* Attach the keypad data to a region in this task. */ + + if (L4Re::Env::env()->rm()->attach(&keymem, mem->size(), L4Re::Rm::Search_addr, + L4::Ipc::make_cap_rw(mem))) + return 1; + + /* Show the keypad state. */ + + keypad = (uint32_t *) keymem; + + while (1) show_keypad(); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/keypad_ds_client/keypad_ds_client_c.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/keypad_ds_client/keypad_ds_client_c.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,178 @@ +/* + * Display the keypad matrix using the specified dimensions. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +/* Video abstractions. */ + +static l4re_util_video_goos_fb_t gfb; +static l4re_video_view_info_t fbi; +static void *fb; + +/* Keypad status and dimensions. */ + +uint32_t *keypad = 0; +void *keymem = 0; +int columns, rows; + + + +static uint32_t bitmask(uint32_t size) +{ + return (1 << size) - 1; +} + +static uint32_t truncate_channel(uint32_t value, uint32_t size) +{ + return (value >> (8 - size)) & bitmask(size); +} + +static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) +{ + if (bpp <= 8) *(uint8_t *) pos = value; + else if (bpp <= 16) *(uint16_t *) pos = value; + else *(uint32_t *) pos = value; +} + +/* Show the state of a key on the display. */ + +static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) +{ + uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); + uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; + uint32_t bytes_per_line = fbi.bytes_per_line; + uint32_t pos; + uint32_t col, row; + + rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | + (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | + (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); + + for (row = 0; row < h; row++) + { + pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; + + for (col = 0; col < w; col++) + { + set_pixel(pos, bpp, rgb); + pos += bytes_per_pixel; + } + } +} + +/* Show the keypad status on the display. */ + +static void show_keypad(void) +{ + uint32_t colsize = fbi.width / columns, + rowsize = fbi.height / rows; + uint8_t column, row; + uint32_t mask; + + for (column = 0; column < columns; column++) + + for (row = 0, mask = 1 << (rows - 1); + row < rows; + row++, mask >>= 1) + + show_keystate(column * colsize, row * rowsize, colsize, rowsize, + keypad[column] & mask ? 0xffffff : 0); + + /* Refresh the display. */ + + l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); +} + + + +int main(int argc, char *argv[]) +{ + l4_cap_idx_t keypad_server; + l4re_ds_t mem; + l4_msgtag_t tag; + + /* Obtain the keypad matrix dimensions. */ + + if (argc < 3) + return 1; + + columns = atoi(argv[1]); + rows = atoi(argv[2]); + + if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) + return 1; + + if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) + return 1; + + if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) + return 1; + + /* Obtain a reference to the keypad. */ + + keypad_server = l4re_env_get_cap("keypad"); + if (l4_is_invalid_cap(keypad_server)) return 1; + + /* Obtain a capability for the keypad data. */ + + mem = l4re_util_cap_alloc(); + if (l4_is_invalid_cap(mem)) return 1; + + /* Obtain a reference to the keypad data. */ + + l4_utcb_br()->bdr = 0; + l4_utcb_br()->br[0] = L4_RCV_ITEM_SINGLE_CAP | mem; + + tag = l4_ipc_call(keypad_server, l4_utcb(), + l4_msgtag(Keypad_op_get_keypad_data, 0, 0, 0), /* zero words, zero *sent* items */ + L4_IPC_NEVER); + + if (l4_ipc_error(tag, l4_utcb())) return 1; + + /* Attach the keypad data to a region in this task. */ + + if (l4re_rm_attach(&keymem, l4re_ds_size(mem), L4RE_RM_SEARCH_ADDR, mem, 0, + L4_PAGESHIFT)) + return 1; + + /* Show the keypad state. */ + + keypad = (uint32_t *) keymem; + + while (1) show_keypad(); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_backlight/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_backlight/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_letux400_backlight +SRC_CC = letux400_backlight.cc +REQUIRES_LIBS = libio l4re_c-util libdevice-backlight-client libdevice-input-keypad libdrivers-keypad-letux400 + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_backlight/letux400_backlight.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_backlight/letux400_backlight.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,109 @@ +/* + * Access the keypad to modify the backlight on the Letux 400. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include + +#include +#include + +/* Backlight level. */ + +enum Letux400_backlight_levels +{ + Letux400_backlight_min_level = 0, + Letux400_backlight_max_level = 300, + Letux400_backlight_step = 25, +}; + +static int backlight_level = 250; + +/* Key state. */ + +static int modifier_set = 0; + +/* Backlight device abstractions. */ + +static L4::Cap backlight_device; + + + +/* Input event handler. */ + +static void handler(Input_event event, void *priv) +{ + (void) priv; + + /* Track the state of the modifier key. */ + + if (event.code == L4RE_KEY_SLEEP) + modifier_set = event.value; + + if (!event.value || !modifier_set) + return; + + /* Upon keypress events, test controls and update the backlight. */ + + switch (event.code) + { + case L4RE_KEY_DOWN: + if (backlight_level < Letux400_backlight_min_level + Letux400_backlight_step) + backlight_level = Letux400_backlight_min_level; + else + backlight_level -= Letux400_backlight_step; + break; + + case L4RE_KEY_UP: + if (backlight_level > Letux400_backlight_max_level - Letux400_backlight_step) + backlight_level = Letux400_backlight_max_level; + else + backlight_level += Letux400_backlight_step; + break; + + default: return; + } + + /* Use the backlight device to update the backlight level. */ + + backlight_device->set_brightness(backlight_level); +} + + + +int main(void) +{ + Keypad *keypad = Keypad::get_keypad(); + Input_keypad_client client(keypad); + + /* Obtain a reference to the PWM device. */ + + backlight_device = L4Re::Env::env()->get_cap("backlight"); + if (!backlight_device.is_valid()) return 1; + + client.attach(handler, 0); + + l4_sleep_forever(); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_keypad/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_letux400_keypad +SRC_C = letux400_keypad.c memory.c +REQUIRES_LIBS = libio l4re_c-util libdrivers-gpio + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad/letux400_keypad.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_keypad/letux400_keypad.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,205 @@ +/* + * Access the keypad GPIOs on the Letux 400 notebook computer. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "memory.h" + +enum Jz4730_keypad_gpio +{ + Jz4730_keypad_gpio_inputs_count = 8, + Jz4730_keypad_gpio_outputs_count = 17, +}; + +/* Port A input pins. */ + +const uint8_t Jz4730_keypad_inputs[Jz4730_keypad_gpio_inputs_count] = { + 0, 1, 2, 3, 4, 5, 6, 7 +}; + +const Pin_slice Jz4730_keypad_inputs_mask = {.mask=0x000000ff, .offset=0}; + +/* Port D output pins. */ + +const uint8_t Jz4730_keypad_outputs[Jz4730_keypad_gpio_outputs_count] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 +}; + +const Pin_slice Jz4730_keypad_outputs_mask = {.mask=0x2000ffff, .offset=0}; + +/* Video abstractions. */ + +static l4re_util_video_goos_fb_t gfb; +static l4re_video_view_info_t fbi; +static void *fb; + +/* Peripheral memory regions. */ + +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; + +/* GPIO abstractions. */ + +static void *gpio_port_a, *gpio_port_d; + +/* Keypad status. */ + +uint32_t keypad[Jz4730_keypad_gpio_outputs_count]; + + + +/* Initialise the pins for scanning the keypad. */ + +static void init_keyscan(void) +{ + jz4730_gpio_multi_setup(gpio_port_a, &Jz4730_keypad_inputs_mask, Fix_input, 0); + jz4730_gpio_multi_config_pull(gpio_port_a, &Jz4730_keypad_inputs_mask, Pull_up); + jz4730_gpio_multi_setup(gpio_port_d, &Jz4730_keypad_outputs_mask, Fix_input, 0); +} + +/* +Scan the keypad by enabling each output column and inspecting each input row. +Store each column bitmap in the keypad array. +*/ + +static void scan_keypad(void) +{ + uint8_t column, row; + uint32_t value; + + for (column = 0; column < Jz4730_keypad_gpio_outputs_count; column++) + { + jz4730_gpio_setup(gpio_port_d, Jz4730_keypad_outputs[column], Fix_output, 0); + l4_sleep(1); + + value = 0; + + for (row = 0; row < Jz4730_keypad_gpio_inputs_count; row++) + value = (value << 1) | (jz4730_gpio_get(gpio_port_a, Jz4730_keypad_inputs[row]) ? 0 : 1); + + keypad[column] = value; + + jz4730_gpio_setup(gpio_port_d, Jz4730_keypad_outputs[column], Fix_input, 0); + } +} + +static uint32_t bitmask(uint32_t size) +{ + return (1 << size) - 1; +} + +static uint32_t truncate_channel(uint32_t value, uint32_t size) +{ + return (value >> (8 - size)) & bitmask(size); +} + +static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) +{ + if (bpp <= 8) *(uint8_t *) pos = value; + else if (bpp <= 16) *(uint16_t *) pos = value; + else *(uint32_t *) pos = value; +} + +/* Show the state of a key on the display. */ + +static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) +{ + uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); + uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; + uint32_t bytes_per_line = fbi.bytes_per_line; + uint32_t pos; + uint32_t col, row; + + rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | + (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | + (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); + + for (row = 0; row < h; row++) + { + pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; + + for (col = 0; col < w; col++) + { + set_pixel(pos, bpp, rgb); + pos += bytes_per_pixel; + } + } +} + +/* Show the keypad status on the display. */ + +static void show_keypad(void) +{ + uint32_t colsize = fbi.width / Jz4730_keypad_gpio_outputs_count, + rowsize = fbi.height / Jz4730_keypad_gpio_inputs_count; + uint8_t column, row; + uint32_t mask; + + for (column = 0; column < Jz4730_keypad_gpio_outputs_count; column++) + + for (row = 0, mask = 1 << (Jz4730_keypad_gpio_inputs_count - 1); + row < Jz4730_keypad_gpio_inputs_count; + row++, mask >>= 1) + + show_keystate(column * colsize, row * rowsize, colsize, rowsize, + keypad[column] & mask ? 0xffffff : 0); + + /* Refresh the display. */ + + l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); +} + +int main(void) +{ + int result; + + if ((result = get_memory("jz4730-gpio", &gpio_virt_base, &gpio_virt_base_end)) < 0) + return 1; + + if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) + return 1; + + if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) + return 1; + + if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) + return 1; + + gpio_port_a = jz4730_gpio_init(gpio_virt_base, gpio_virt_base + 0x30, 32); + gpio_port_d = jz4730_gpio_init(gpio_virt_base + 0x90, gpio_virt_base + 0xc0, 32); + + init_keyscan(); + + while (1) + { + scan_keypad(); + show_keypad(); + } + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad/memory.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_keypad/memory.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,105 @@ +/* + * Memory allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * Subject to other copyrights, being derived from the existing L4Re + * LCD driver implementations. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#include + +#include "memory.h" +#include +#include +#include +#include +#include +#include + +/* Internal memory allocation/mapping functions. */ + +static char const *resource_type(enum l4io_resource_types_t type) +{ + switch (type) + { + case L4VBUS_RESOURCE_INVALID: + return "INVALID"; + + case L4VBUS_RESOURCE_IRQ: + return "IRQ"; + + case L4VBUS_RESOURCE_MEM: + return "MEMORY"; + + default: + return "OTHER"; + } +} + +int get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) +{ + int result = l4io_lookup_device(hid, dh, 0, rh); + + if (result < 0) + printf("Could not access '%s': %s\n", hid, result == -L4_ENOENT ? "no such device" : "no device"); + + return result; +} + +int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type) +{ + int current = 0, result = 0; + l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); + + do + { + result = l4vbus_get_resource(vbus, dh, current, res); + + if (result) + printf("Could not access resource of type %s.\n", resource_type(type)); + else + printf("Resource %d: type %s, start=%lx, end=%lx\n", res->id, + resource_type(res->type), res->start, res->end); + + current++; + } + while ((!result) && (res->type != type)); + + return result; +} + +int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = get_resource(dh, &res, L4IO_RESOURCE_MEM); + + if (result) + return result; + + if ((result = l4io_request_iomem(res.start, res.end - res.start + 1, + L4IO_MEM_NONCACHED, start))) + { + printf("Could not get address for '%s'.\n", hid); + return result; + } + + printf("Resource at 0x%lx...0x%lx.\n", res.start, res.end); + + *end = *start + (res.end - res.start + 1); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad/memory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_keypad/memory.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,28 @@ +/* + * Memory allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * Subject to other copyrights, being derived from the existing L4Re + * LCD driver implementations. + * + * This file is part of TUD:OS and distributed under the terms of the + * GNU General Public License 2. + * Please see the COPYING-GPL-2 file for details. + */ + +#ifndef __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ +#define __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ + +#include +#include +#include + +int get_device(char const *hid, l4io_device_handle_t *dh, + l4io_resource_handle_t *rh); + +int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type); + +int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end); + +#endif /* __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ */ diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad_driver/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_keypad_driver/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,9 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_letux400_keypad_driver +SRC_CC = letux400_keypad_driver.cc +SRC_DATA = unifont.tff +REQUIRES_LIBS = libio l4re_c-util libdevice-input-keypad libdrivers-keypad-letux400 mag-gfx + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad_driver/letux400_keypad_driver.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_keypad_driver/letux400_keypad_driver.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,251 @@ +/* + * Access the keypad on the configured device using an input driver. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Font definitions and licence (see unifont.tff for bitmap data derived from + * GNU Unifont's unifont.hex file): + * + * Copyright (C) 1998-2003 Roman Czyborra (http://czyborra.com/) + * + * All glyphs are released under the GNU General Public License + * (GPL) version 2 or (at your option) a later version, with the + * GNU font embedding exception: + * + * ** GPL v2.0 license with font embedding exception: + * + * As a special exception, if you create a document which + * uses this font, and embed this font or unaltered portions + * of this font into the document, this font does not by + * itself cause the resulting document to be covered by + * the GNU General Public License. This exception does not + * however invalidate any other reasons why the document + * might be covered by the GNU General Public License. + * If you modify this font, you may extend this exception + * to your version of the font, but you are not obligated + * to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* Video abstractions. */ + +static l4re_util_video_goos_fb_t gfb; +static l4re_video_view_info_t view_info; +static void *fb = 0; + +/* Bundled font data. */ + +extern char const _binary_unifont_tff_start[]; + +/* Screen abstractions. */ + +using namespace Mag_gfx; + +static Font *_font = 0; +static Canvas *_screen = 0; + + + +/* Factories for certain pixel formats. */ + +static Mem::Factory _rgb16; +static Mem::Factory _rgb32; + + + +/* Key to character conversion function. */ + +static const char *keys_to_strings[] = { + + 0, "Escape", "1", "2", "3", "4", "5", "6", "7", "8", + + "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E", "R", + + "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Left Ctrl", + + "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", + + "'", "`", "Left Shift", "\\", "Z", "X", "C", "V", "B", "N", + + "M", ",", ".", "/", "Right Shift", "Keypad *", "Left Alt", "Space", + "Caps Lock", "F1", + + "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "Num Lock", + + "Scroll Lock", "Keypad 7", "Keypad 8", "Keypad 9", "Keypad -", "Keypad 4", + "Keypad 5", "Keypad 6", "Keypad +", "Keypad 1", + + "Keypad 2", "Keypad 3", "Keypad 0", "Keypad .", 0, 0, "#102", "F11", "F12", 0, + + 0, 0, 0, 0, 0, 0, "Keypad Enter", "Right Ctrl", "Keypad /", "SysRq", + + "Right Alt", "Line Feed", "Home", "Up", "Page Up", "Left", "Right", "End", + "Down", "Page Down", + + "Insert", "Delete", "Macro", "Mute", "Volume Down", "Volume Up", "Power", + "Keypad =", "Keypad +-", "Pause", +}; + +static const char null_string[] = "Unknown"; + +const int keys_to_strings_length = 120; + +static const char *key_to_string(int key) +{ + return key < keys_to_strings_length ? keys_to_strings[key] : 0; +} + +/* Show the keypad event status on the display. */ + +static uint8_t row = 0; +static uint32_t text_x = 0, text_y = 0, next_y = 0; + +static void handler(Input_event event, void *priv) +{ + uint32_t colsize = view_info.width / 10, + rowsize = view_info.height / 20; + uint8_t column; + uint16_t mask; + + /* Convert the key code into a bit pattern. */ + + if (!priv) + { + for (column = 0, mask = (1 << 9); column < 10; column++, mask >>= 1) + _screen->draw_box(Rect(Point(column * colsize, row * rowsize), Area(colsize, rowsize)), + event.code & mask ? event.value ? Rgb32::Color(0, 255, 0) : Rgb32::Color(255, 0, 0) + : Rgb32::Color(0, 0, 0)); + + /* Advance to the next row, wrapping around. */ + + row = (row + 1) % 20; + } + + /* Or produce a string. */ + + else if (event.value) + { + const char *s = ((const char *(*)(int)) priv)(event.code); + Rgba32::Color col; + + if (!s) + { + s = null_string; + col = Rgba32::Color(255, 0, 0, Rgba32::Color::Amax); + } + else + col = Rgba32::Color(255, 255, 255, Rgba32::Color::Amax); + + Area box = _font->str_sz(s, strlen(s)); + + /* Test for enough space horizontally. */ + + if (text_x + box.w() > view_info.width) + { + text_x = 0; + text_y = next_y; + next_y = text_y + box.h(); + } + + /* Expand the line height, if appropriate. */ + + else if (text_y + box.h() > next_y) + next_y += box.h(); + + /* Test for enough space vertically. */ + + if (next_y > view_info.height) + { + text_x = 0; + text_y = 0; + next_y = box.h(); + } + + Point p(text_x, text_y); + + _screen->draw_box(Rect(p, box), Rgb32::Color(0, 0, 0)); + _screen->draw_string(p, _font, col, s, strlen(s)); + + /* Move to the next position. */ + + text_x += box.w(); + } + + /* Refresh the display. */ + + l4re_util_video_goos_fb_refresh(&gfb, 0, 0, view_info.width, view_info.height); +} + +/* Arguments: [ chars ] */ + +int main(int argc, char *argv[]) +{ + Keypad *keypad = Keypad::get_keypad(); + Input_keypad_client client(keypad); + + if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) + return 1; + + if (l4re_util_video_goos_fb_view_info(&gfb, &view_info)) + return 1; + + if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) + return 1; + + /* Obtain a canvas for the framebuffer. */ + + Factory *factory; + + if (view_info.pixel_info.bytes_per_pixel == 2) + factory = &_rgb16; + else + factory = &_rgb32; + + Canvas *screen = factory->create_canvas((void *) ((unsigned long) fb + view_info.buffer_offset), + Area(view_info.width, view_info.height), + view_info.bytes_per_line); + + Font font(&_binary_unifont_tff_start[0]); + + _screen = screen; + _font = &font; + + /* Attach the event handler and wait for events. */ + + client.attach(handler, (argc > 1) && (!strcmp(argv[1], "chars")) ? (void *) key_to_string : 0); + + l4_sleep_forever(); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad_driver/unifont.tff Binary file pkg/landfall-examples/letux400_keypad_driver/unifont.tff has changed diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad_physical/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_keypad_physical/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_letux400_keypad_physical +SRC_C = letux400_keypad_physical.c +REQUIRES_LIBS = l4re_c-util + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_keypad_physical/letux400_keypad_physical.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_keypad_physical/letux400_keypad_physical.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,314 @@ +/* + * Display the physical keypad matrix layout for the Letux 400 notebook + * computer. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +enum Jz4730_keypad_gpio +{ + Jz4730_keypad_gpio_inputs_count = 8, + Jz4730_keypad_gpio_outputs_count = 17, +}; + +/* Video abstractions. */ + +static l4re_util_video_goos_fb_t gfb; +static l4re_video_view_info_t fbi; +static void *fb; + +/* Keypad status and dimensions. */ + +uint32_t *keypad = 0; +void *keymem = 0; +int columns = Jz4730_keypad_gpio_outputs_count, rows = Jz4730_keypad_gpio_inputs_count; + +/* Position units: 0.1mm */ + +enum { + SPC = 600, CAPS = 240, TAB = 200, LSH = 184, M = 160, S = 136, XS = 120, + WIDTH = 2040, HEIGHT = 800, ROWS = 6, +}; + +/* +S(15) Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 Num Sys Ins Del +XS(1)/M(12) ` 1 2 3 4 5 6 7 8 9 0 - Bsp +TAB(1)/M(10)/XS(2) Tab Q W E R T Y U I O P = \ +CAPS(1)/M(9)/XS(1)/CAPS(1) Caps A S D F G H J K L ; Enter +LSH(1)/XS(1)/M(7)/XS(4)/S(1) Sh \ Z X C V B N M , . / Up Sh +XS(5)/SPC(1)/XS(7) Fn Ctr Zzz Alt Pau Space Mnu [ ] ' Lt Dn Rt +*/ + +enum { + SIZE_KEY_ESC = S, SIZE_KEY_F1 = S, SIZE_KEY_F2 = S, SIZE_KEY_F3 = S, SIZE_KEY_F4 = S, + SIZE_KEY_F5 = S, SIZE_KEY_F6 = S, SIZE_KEY_F7 = S, SIZE_KEY_F8 = S, SIZE_KEY_F9 = S, + SIZE_KEY_F10 = S, SIZE_KEY_NUMLOCK = S, SIZE_KEY_SYSRQ = S, SIZE_KEY_INSERT = S, + SIZE_KEY_DELETE = S, + + SIZE_KEY_GRAVE = XS, SIZE_KEY_1 = M, SIZE_KEY_2 = M, SIZE_KEY_3 = M, SIZE_KEY_4 = M, + SIZE_KEY_5 = M, SIZE_KEY_6 = M, SIZE_KEY_7 = M, SIZE_KEY_8 = M, SIZE_KEY_9 = M, + SIZE_KEY_0 = M, SIZE_KEY_MINUS = M, SIZE_KEY_BACKSPACE = M, + + SIZE_KEY_TAB = TAB, SIZE_KEY_Q = M, SIZE_KEY_W = M, SIZE_KEY_E = M, SIZE_KEY_R = M, + SIZE_KEY_T = M, SIZE_KEY_Y = M, SIZE_KEY_U = M, SIZE_KEY_I = M, SIZE_KEY_O = M, + SIZE_KEY_P = M, SIZE_KEY_EQUAL = XS, SIZE_KEY_RIGHTBACKSLASH = XS, + + SIZE_KEY_CAPSLOCK = CAPS, SIZE_KEY_A = M, SIZE_KEY_S = M, SIZE_KEY_D = M, SIZE_KEY_F = M, + SIZE_KEY_G = M, SIZE_KEY_H = M, SIZE_KEY_J = M, SIZE_KEY_K = M, SIZE_KEY_L = M, + SIZE_KEY_SEMICOLON = XS, SIZE_KEY_ENTER = CAPS, + + SIZE_KEY_LEFTSHIFT = LSH, SIZE_KEY_LEFTBACKSLASH = XS, SIZE_KEY_Z = M, SIZE_KEY_X = M, SIZE_KEY_C = M, + SIZE_KEY_V = M, SIZE_KEY_B = M, SIZE_KEY_N = M, SIZE_KEY_M = M, SIZE_KEY_COMMA = XS, + SIZE_KEY_DOT = XS, SIZE_KEY_SLASH = XS, SIZE_KEY_UP = XS, SIZE_KEY_RIGHTSHIFT = S, + + SIZE_KEY_FN = XS, SIZE_KEY_LEFTCTRL = XS, SIZE_KEY_SLEEP = XS, SIZE_KEY_LEFTALT = XS, SIZE_KEY_PAUSE = XS, + SIZE_KEY_SPACE = SPC, SIZE_KEY_MENU = XS, SIZE_KEY_LEFTBRACE = XS, SIZE_KEY_RIGHTBRACE = XS, + SIZE_KEY_APOSTROPHE = XS, SIZE_KEY_LEFT = XS, SIZE_KEY_DOWN = XS, SIZE_KEY_RIGHT = XS, +}; + +enum { + XPOS_KEY_ESC = 0, XPOS_KEY_F1 = S, XPOS_KEY_F2 = 2*S, XPOS_KEY_F3 = 3*S, XPOS_KEY_F4 = 4*S, + XPOS_KEY_F5 = 5*S, XPOS_KEY_F6 = 6*S, XPOS_KEY_F7 = 7*S, XPOS_KEY_F8 = 8*S, XPOS_KEY_F9 = 9*S, + XPOS_KEY_F10 = 10*S, XPOS_KEY_NUMLOCK = 11*S, XPOS_KEY_SYSRQ = 12*S, XPOS_KEY_INSERT = 13*S, + XPOS_KEY_DELETE = 14*S, + + XPOS_KEY_GRAVE = 0, XPOS_KEY_1 = XS, XPOS_KEY_2 = XS+M, XPOS_KEY_3 = XS+2*M, XPOS_KEY_4 = XS+3*M, + XPOS_KEY_5 = XS+4*M, XPOS_KEY_6 = XS+5*M, XPOS_KEY_7 = XS+6*M, XPOS_KEY_8 = XS+7*M, XPOS_KEY_9 = XS+8*M, + XPOS_KEY_0 = XS+9*M, XPOS_KEY_MINUS = XS+10*M, XPOS_KEY_BACKSPACE = XS+11*M, + + XPOS_KEY_TAB = 0, XPOS_KEY_Q = TAB, XPOS_KEY_W = TAB+M, XPOS_KEY_E = TAB+2*M, XPOS_KEY_R = TAB+3*M, + XPOS_KEY_T = TAB+4*M, XPOS_KEY_Y = TAB+5*M, XPOS_KEY_U = TAB+6*M, XPOS_KEY_I = TAB+7*M, XPOS_KEY_O = TAB+8*M, + XPOS_KEY_P = TAB+9*M, XPOS_KEY_EQUAL = TAB+10*M, XPOS_KEY_RIGHTBACKSLASH = TAB+10*M+XS, + + XPOS_KEY_CAPSLOCK = 0, XPOS_KEY_A = CAPS, XPOS_KEY_S = CAPS+M, XPOS_KEY_D = CAPS+2*M, XPOS_KEY_F = CAPS+3*M, + XPOS_KEY_G = CAPS+4*M, XPOS_KEY_H = CAPS+5*M, XPOS_KEY_J = CAPS+6*M, XPOS_KEY_K = CAPS+7*M, XPOS_KEY_L = CAPS+8*M, + XPOS_KEY_SEMICOLON = CAPS+9*M, XPOS_KEY_ENTER = CAPS+9*M+XS, + + XPOS_KEY_LEFTSHIFT = 0, XPOS_KEY_LEFTBACKSLASH = LSH, XPOS_KEY_Z = LSH+XS, XPOS_KEY_X = LSH+XS+M, XPOS_KEY_C = LSH+XS+2*M, + XPOS_KEY_V = LSH+XS+3*M, XPOS_KEY_B = LSH+XS+4*M, XPOS_KEY_N = LSH+XS+5*M, XPOS_KEY_M = LSH+XS+6*M, XPOS_KEY_COMMA = LSH+XS+7*M, + XPOS_KEY_DOT = LSH+XS+7*M+XS, XPOS_KEY_SLASH = LSH+XS+7*M+2*XS, XPOS_KEY_UP = LSH+XS+7*M+3*XS, XPOS_KEY_RIGHTSHIFT = LSH+XS+7*M+4*XS, + + XPOS_KEY_FN = 0, XPOS_KEY_LEFTCTRL = XS, XPOS_KEY_SLEEP = 2*XS, XPOS_KEY_LEFTALT = 3*XS, XPOS_KEY_PAUSE = 4*XS, + XPOS_KEY_SPACE = 5*XS, XPOS_KEY_MENU = 5*XS+SPC, XPOS_KEY_LEFTBRACE = 5*XS+SPC+XS, XPOS_KEY_RIGHTBRACE = 5*XS+SPC+2*XS, + XPOS_KEY_APOSTROPHE = 5*XS+SPC+3*XS, XPOS_KEY_LEFT = 5*XS+SPC+4*XS, XPOS_KEY_DOWN = 5*XS+SPC+5*XS, XPOS_KEY_RIGHT = 5*XS+SPC+6*XS, +}; + +enum { + YPOS_KEY_ESC = 0, YPOS_KEY_F1 = 0, YPOS_KEY_F2 = 0, YPOS_KEY_F3 = 0, YPOS_KEY_F4 = 0, + YPOS_KEY_F5 = 0, YPOS_KEY_F6 = 0, YPOS_KEY_F7 = 0, YPOS_KEY_F8 = 0, YPOS_KEY_F9 = 0, + YPOS_KEY_F10 = 0, YPOS_KEY_NUMLOCK = 0, YPOS_KEY_SYSRQ = 0, YPOS_KEY_INSERT = 0, + YPOS_KEY_DELETE = 0, + + YPOS_KEY_GRAVE = 1, YPOS_KEY_1 = 1, YPOS_KEY_2 = 1, YPOS_KEY_3 = 1, YPOS_KEY_4 = 1, + YPOS_KEY_5 = 1, YPOS_KEY_6 = 1, YPOS_KEY_7 = 1, YPOS_KEY_8 = 1, YPOS_KEY_9 = 1, + YPOS_KEY_0 = 1, YPOS_KEY_MINUS = 1, YPOS_KEY_BACKSPACE = 1, + + YPOS_KEY_TAB = 2, YPOS_KEY_Q = 2, YPOS_KEY_W = 2, YPOS_KEY_E = 2, YPOS_KEY_R = 2, + YPOS_KEY_T = 2, YPOS_KEY_Y = 2, YPOS_KEY_U = 2, YPOS_KEY_I = 2, YPOS_KEY_O = 2, + YPOS_KEY_P = 2, YPOS_KEY_EQUAL = 2, YPOS_KEY_RIGHTBACKSLASH = 2, + + YPOS_KEY_CAPSLOCK = 3, YPOS_KEY_A = 3, YPOS_KEY_S = 3, YPOS_KEY_D = 3, YPOS_KEY_F = 3, + YPOS_KEY_G = 3, YPOS_KEY_H = 3, YPOS_KEY_J = 3, YPOS_KEY_K = 3, YPOS_KEY_L = 3, + YPOS_KEY_SEMICOLON = 3, YPOS_KEY_ENTER = 3, + + YPOS_KEY_LEFTSHIFT = 4, YPOS_KEY_LEFTBACKSLASH = 4, YPOS_KEY_Z = 4, YPOS_KEY_X = 4, YPOS_KEY_C = 4, + YPOS_KEY_V = 4, YPOS_KEY_B = 4, YPOS_KEY_N = 4, YPOS_KEY_M = 4, YPOS_KEY_COMMA = 4, + YPOS_KEY_DOT = 4, YPOS_KEY_SLASH = 4, YPOS_KEY_UP = 4, YPOS_KEY_RIGHTSHIFT = 4, + + YPOS_KEY_FN = 5, YPOS_KEY_LEFTCTRL = 5, YPOS_KEY_SLEEP = 5, YPOS_KEY_LEFTALT = 5, YPOS_KEY_PAUSE = 5, + YPOS_KEY_SPACE = 5, YPOS_KEY_MENU = 5, YPOS_KEY_LEFTBRACE = 5, YPOS_KEY_RIGHTBRACE = 5, + YPOS_KEY_APOSTROPHE = 5, YPOS_KEY_LEFT = 5, YPOS_KEY_DOWN = 5, YPOS_KEY_RIGHT = 5, +}; + +/* Keypad matrix mapping. */ + +#define PHYS_KEY(X) {XPOS_KEY_##X, YPOS_KEY_##X, SIZE_KEY_##X} +#define PHYS_NULL {0, 0, 0} + +static const uint32_t keypos[Jz4730_keypad_gpio_inputs_count][Jz4730_keypad_gpio_outputs_count][3] = { + +{PHYS_KEY(PAUSE), PHYS_KEY(Q), PHYS_KEY(W), PHYS_KEY(E), PHYS_KEY(R), PHYS_KEY(U), PHYS_KEY(I), PHYS_KEY(O), + PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(P), PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_NULL}, + +{PHYS_NULL, PHYS_KEY(TAB), PHYS_KEY(CAPSLOCK), PHYS_KEY(F3), PHYS_KEY(T), PHYS_KEY(Y), PHYS_KEY(RIGHTBRACE), PHYS_KEY(F7), + PHYS_NULL, PHYS_KEY(BACKSPACE), PHYS_NULL, PHYS_KEY(LEFTBRACE), PHYS_KEY(SLEEP), PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(LEFTSHIFT)}, + +{PHYS_NULL, PHYS_KEY(A), PHYS_KEY(S), PHYS_KEY(D), PHYS_KEY(F), PHYS_KEY(J), PHYS_KEY(K), PHYS_KEY(L), + PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(SEMICOLON), PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(UP), PHYS_KEY(RIGHTSHIFT)}, + +{PHYS_NULL, PHYS_KEY(ESC), PHYS_KEY(LEFTBACKSLASH), PHYS_KEY(F4), PHYS_KEY(G), PHYS_KEY(H), PHYS_KEY(F6), PHYS_NULL, + PHYS_KEY(SPACE), PHYS_NULL, PHYS_KEY(LEFTALT), PHYS_KEY(APOSTROPHE), PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(DOWN), PHYS_NULL}, + +{PHYS_NULL, PHYS_KEY(Z), PHYS_KEY(X), PHYS_KEY(C), PHYS_KEY(V), PHYS_KEY(M), PHYS_KEY(COMMA), PHYS_KEY(DOT), + PHYS_KEY(NUMLOCK), PHYS_KEY(ENTER), PHYS_NULL, PHYS_KEY(RIGHTBACKSLASH), PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(LEFT), PHYS_NULL}, + +{PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(B), PHYS_KEY(N), PHYS_NULL, PHYS_KEY(MENU), + PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(SLASH), PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(RIGHT), PHYS_NULL}, + +{PHYS_KEY(LEFTCTRL), PHYS_KEY(GRAVE), PHYS_NULL, PHYS_NULL, PHYS_KEY(5), PHYS_KEY(6), PHYS_KEY(EQUAL), PHYS_KEY(F8), + PHYS_KEY(DELETE), PHYS_KEY(F9), PHYS_NULL, PHYS_KEY(MINUS), PHYS_NULL, PHYS_KEY(F2), PHYS_KEY(INSERT), PHYS_NULL, PHYS_KEY(F1)}, + +{PHYS_KEY(F5), PHYS_KEY(1), PHYS_KEY(2), PHYS_KEY(3), PHYS_KEY(4), PHYS_KEY(7), PHYS_KEY(8), PHYS_KEY(9), + PHYS_NULL, PHYS_NULL, PHYS_KEY(SYSRQ), PHYS_KEY(0), PHYS_KEY(F10), PHYS_NULL, PHYS_NULL, PHYS_NULL, PHYS_KEY(FN)} +}; + + + +static uint32_t bitmask(uint32_t size) +{ + return (1 << size) - 1; +} + +static uint32_t truncate_channel(uint32_t value, uint32_t size) +{ + return (value >> (8 - size)) & bitmask(size); +} + +static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) +{ + if (bpp <= 8) *(uint8_t *) pos = value; + else if (bpp <= 16) *(uint16_t *) pos = value; + else *(uint32_t *) pos = value; +} + +/* Show the state of a key on the display. */ + +static void fill_rectangle(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) +{ + uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); + uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; + uint32_t bytes_per_line = fbi.bytes_per_line; + uint32_t pos; + uint32_t col, row; + + rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | + (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | + (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); + + for (row = 0; row < h; row++) + { + pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; + + for (col = 0; col < w; col++) + { + set_pixel(pos, bpp, rgb); + pos += bytes_per_pixel; + } + } +} + +/* Show the keypad status on the display. */ + +static void show_keypad(void) +{ + uint32_t rowsize = fbi.height / ROWS, colsize; + uint8_t column, row; + uint32_t mask; + const uint32_t *pos; + + for (column = 0; column < columns; column++) + + for (row = 0, mask = 1 << (rows - 1); + row < rows; + row++, mask >>= 1) + { + /* Obtain the physical position. */ + + pos = keypos[row][column]; + + /* Obtain the width of the key. */ + + colsize = (pos[2] * fbi.width) / WIDTH; + + /* Plot the rectangle for the key. */ + + fill_rectangle((pos[0] * fbi.width) / WIDTH, pos[1] * rowsize, colsize, rowsize, + keypad[column] & mask ? 0xffffff : 0); + } + + /* Refresh the display. */ + + l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); +} + + + +int main(void) +{ + l4_cap_idx_t keypad_server; + l4re_ds_t mem; + l4_msgtag_t tag; + + if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) + return 1; + + if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) + return 1; + + if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) + return 1; + + /* Obtain a reference to the keypad. */ + + keypad_server = l4re_env_get_cap("keypad"); + if (l4_is_invalid_cap(keypad_server)) return 1; + + /* Obtain a capability for the keypad data. */ + + mem = l4re_util_cap_alloc(); + if (l4_is_invalid_cap(mem)) return 1; + + /* Obtain a reference to the keypad data. */ + + l4_utcb_br()->bdr = 0; + l4_utcb_br()->br[0] = L4_RCV_ITEM_SINGLE_CAP | mem; + + tag = l4_ipc_call(keypad_server, l4_utcb(), + l4_msgtag(0, 0, 0, 0), /* label zero, zero words, zero *sent* items */ + L4_IPC_NEVER); + + if (l4_ipc_error(tag, l4_utcb())) return 1; + + /* Attach the keypad data to a region in this task. */ + + if (l4re_rm_attach(&keymem, l4re_ds_size(mem), L4RE_RM_SEARCH_ADDR, mem, 0, + L4_PAGESHIFT)) + return 1; + + /* Show the keypad state. */ + + keypad = (uint32_t *) keymem; + + while (1) show_keypad(); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_leds/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_leds/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_letux400_leds +SRC_C = letux400_leds.c +REQUIRES_LIBS = libio l4re_c-util libdrivers-gpio libdrivers-pwm + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/letux400_leds/letux400_leds.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/letux400_leds/letux400_leds.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,197 @@ +/* + * Access the LED and PWM GPIOs on the Letux 400 notebook computer. + * This example shows how to use the following GPIOs: + * + * PA27 - Caps Lock + * PC22 - Num Lock + * PC30 - PWM backlight + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +enum { + CAPS = 27, // via PORTA + NUM = 22, // via PORTC + PWM = 30, // via PORTC +}; + + + +/* Device and resource discovery. */ + +static char const *resource_type(enum l4io_resource_types_t type) +{ + switch (type) + { + case L4VBUS_RESOURCE_INVALID: + return "INVALID"; + + case L4VBUS_RESOURCE_IRQ: + return "IRQ"; + + case L4VBUS_RESOURCE_MEM: + return "MEMORY"; + + default: + return "OTHER"; + } +} + +static int get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) +{ + int result = l4io_lookup_device(hid, dh, 0, rh); + + if (result < 0) + printf("Could not access '%s': %s\n", hid, result == -L4_ENOENT ? "no such device" : "no device"); + + return result; +} + +static int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type) +{ + int current = 0, result = 0; + l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); + + do + { + result = l4vbus_get_resource(vbus, dh, current, res); + + if (result) + printf("Could not access resource of type %s.\n", resource_type(type)); + else + printf("Resource %d: type %s, start=%lx, end=%lx\n", res->id, + resource_type(res->type), res->start, res->end); + + current++; + } + while ((!result) && (res->type != type)); + + return result; +} + +static int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = get_resource(dh, &res, L4IO_RESOURCE_MEM); + + if (result) + return result; + + if ((result = l4io_request_iomem(res.start, res.end - res.start + 1, + L4IO_MEM_NONCACHED, start))) + { + printf("Could not get address for '%s'.\n", hid); + return result; + } + + printf("Resource at 0x%lx...0x%lx.\n", res.start, res.end); + + *end = *start + (res.end - res.start + 1); + + return 0; +} + +int main(void) +{ + l4_addr_t gpio_base = 0, gpio_base_end = 0, port_a, port_a_end, port_c, port_c_end; + l4_addr_t pwm_base = 0, pwm_base_end = 0; + void *gpio_port_a, *gpio_port_c, *pwm0_device; + int result = 0; + int caps = 0, num = 1, pwm = 300, pwmdir = -50; + + /* Obtain resource details describing the I/O memory. */ + + printf("Access GPIO...\n"); + + if ((result = get_memory("jz4730-gpio", &gpio_base, &gpio_base_end)) < 0) + return 1; + + port_a = gpio_base; + port_a_end = port_a + 0x30; + port_c = gpio_base + 0x60; + port_c_end = port_c + 0x30; + + printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end); + printf("PORTA at 0x%lx...0x%lx.\n", port_a, port_a_end); + printf("PORTC at 0x%lx...0x%lx.\n", port_c, port_c_end); + + gpio_port_a = jz4730_gpio_init(port_a, port_a_end, 32); + gpio_port_c = jz4730_gpio_init(port_c, port_c_end, 32); + + printf("Access PWM...\n"); + + if ((result = get_memory("jz4730-pwm", &pwm_base, &pwm_base_end)) < 0) + return 1; + + pwm0_device = jz4730_pwm_init(pwm_base, pwm_base + 0x1000); + + /* Set the GPIO pins up. */ + + printf("Set up GPIO pins...\n"); + + jz4730_gpio_setup(gpio_port_a, CAPS, Fix_output, caps); + jz4730_gpio_setup(gpio_port_c, NUM, Fix_output, num); + jz4730_gpio_config_pad(gpio_port_c, PWM, Function_alt, 1); + + /* Set the PWM device up. */ + + printf("Set up PWM...\n"); + + jz4730_pwm_set_duty(pwm0_device, pwm); + jz4730_pwm_set_period(pwm0_device, 299); + jz4730_pwm_set_control(pwm0_device, 0x80 | 0x3f); + + while (1) + { + caps = 1 - caps; + jz4730_gpio_set(gpio_port_a, CAPS, caps); + num = 1 - num; + jz4730_gpio_set(gpio_port_c, NUM, num); + pwm += pwmdir; + jz4730_pwm_set_duty(pwm0_device, pwm); + if (pwm == 0) pwmdir = 50; else if (pwm == 300) pwmdir = -50; + l4_sleep(1000); // 1000ms + } + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_backlight/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_backlight/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_qi_lb60_backlight +SRC_CC = qi_lb60_backlight.cc +REQUIRES_LIBS = libio l4re_c-util libdevice-backlight-client libdevice-input-keypad libdrivers-keypad-qi_lb60 + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_backlight/qi_lb60_backlight.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_backlight/qi_lb60_backlight.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,109 @@ +/* + * Access the keypad to modify the backlight on the Ben NanoNote. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include + +#include +#include + +/* Backlight level. */ + +enum Qi_lb60_backlight_levels +{ + Qi_lb60_backlight_min_level = 0, + Qi_lb60_backlight_max_level = 255, + Qi_lb60_backlight_step = 10, +}; + +static int backlight_level = 64; + +/* Key state. */ + +static int modifier_set = 0; + +/* Backlight device abstractions. */ + +static L4::Cap backlight_device; + + + +/* Input event handler. */ + +static void handler(Input_event event, void *priv) +{ + (void) priv; + + /* Track the state of the modifier key. */ + + if (event.code == L4RE_KEY_FN) + modifier_set = event.value; + + if (!event.value || !modifier_set) + return; + + /* Upon keypress events, test controls and update the backlight. */ + + switch (event.code) + { + case L4RE_KEY_VOLUMEDOWN: + if (backlight_level < Qi_lb60_backlight_min_level + Qi_lb60_backlight_step) + backlight_level = Qi_lb60_backlight_min_level; + else + backlight_level -= Qi_lb60_backlight_step; + break; + + case L4RE_KEY_VOLUMEUP: + if (backlight_level > Qi_lb60_backlight_max_level - Qi_lb60_backlight_step) + backlight_level = Qi_lb60_backlight_max_level; + else + backlight_level += Qi_lb60_backlight_step; + break; + + default: return; + } + + /* Use the backlight device to update the backlight level. */ + + backlight_device->set_brightness(backlight_level); +} + + + +int main(void) +{ + Keypad *keypad = Keypad::get_keypad(); + Input_keypad_client client(keypad); + + /* Obtain a reference to the backlight device. */ + + backlight_device = L4Re::Env::env()->get_cap("backlight"); + if (!backlight_device.is_valid()) return 1; + + client.attach(handler, 0); + + l4_sleep_forever(); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_keypad/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_qi_lb60_keypad +SRC_C = qi_lb60_keypad.c memory.c +REQUIRES_LIBS = libio l4re_c-util libdrivers-gpio + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad/memory.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_keypad/memory.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,78 @@ +/* + * Memory allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include + +#include "memory.h" + +int get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) +{ + return l4io_lookup_device(hid, dh, 0, rh); +} + +int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type) +{ + int current = 0, result = 0; + l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); + + do + { + result = l4vbus_get_resource(vbus, dh, current, res); + current++; + } + while ((!result) && (res->type != type)); + + return result; +} + +int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = get_resource(dh, &res, L4IO_RESOURCE_MEM); + + if (result) + return result; + + result = l4io_request_iomem(res.start, res.end - res.start + 1, + L4IO_MEM_NONCACHED, start); + + if (result) + return result; + + *end = *start + (res.end - res.start + 1); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad/memory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_keypad/memory.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,36 @@ +/* + * Memory allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#ifndef __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ +#define __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ + +#include +#include + +int get_device(char const *hid, l4io_device_handle_t *dh, + l4io_resource_handle_t *rh); + +int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type); + +int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end); + +#endif /* __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ */ diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad/qi_lb60_keypad.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_keypad/qi_lb60_keypad.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,203 @@ +/* + * Access the keypad GPIOs on the Ben NanoNote. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "memory.h" + +enum Jz4740_keypad_gpio +{ + Jz4740_keypad_gpio_inputs_count = 8, + Jz4740_keypad_gpio_outputs_count = 8, +}; + +/* Port D input pins. */ + +const uint8_t Jz4740_keypad_inputs[Jz4740_keypad_gpio_inputs_count] = { + 18, 19, 20, 21, 22, 23, 24, 26 +}; + +const Pin_slice Jz4740_keypad_inputs_mask = {.mask = 0x05fc0000, .offset = 0}; + +/* Port C output pins. */ + +const uint8_t Jz4740_keypad_outputs[Jz4740_keypad_gpio_outputs_count] = { + 10, 11, 12, 13, 14, 15, 16, 17 +}; + +const Pin_slice Jz4740_keypad_outputs_mask = {.mask = 0x0003fc00, .offset = 0}; + +/* Video abstractions. */ + +static l4re_util_video_goos_fb_t gfb; +static l4re_video_view_info_t fbi; +static void *fb; + +/* Peripheral memory regions. */ + +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; + +/* GPIO abstractions. */ + +static void *gpio_port_c, *gpio_port_d; + +/* Keypad status. */ + +uint8_t keypad[Jz4740_keypad_gpio_outputs_count]; + + + +/* Initialise the pins for scanning the keypad. */ + +static void init_keyscan(void) +{ + jz4740_gpio_multi_setup(gpio_port_d, &Jz4740_keypad_inputs_mask, Fix_input, 0); + jz4740_gpio_multi_config_pull(gpio_port_d, &Jz4740_keypad_inputs_mask, Pull_up); + jz4740_gpio_multi_setup(gpio_port_c, &Jz4740_keypad_outputs_mask, Fix_input, 0); +} + +/* +Scan the keypad by enabling each output column and inspecting each input row. +Store each column bitmap in the keypad array. +*/ + +static void scan_keypad(void) +{ + uint8_t column, row, value; + + for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++) + { + jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Fix_output, 0); + l4_sleep(1); + + value = 0; + + for (row = 0; row < Jz4740_keypad_gpio_inputs_count; row++) + value = (value << 1) | (jz4740_gpio_get(gpio_port_d, Jz4740_keypad_inputs[row]) ? 0 : 1); + + keypad[column] = value; + + jz4740_gpio_setup(gpio_port_c, Jz4740_keypad_outputs[column], Fix_input, 0); + } +} + +static uint32_t bitmask(uint32_t size) +{ + return (1 << size) - 1; +} + +static uint32_t truncate_channel(uint32_t value, uint32_t size) +{ + return (value >> (8 - size)) & bitmask(size); +} + +static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) +{ + if (bpp <= 8) *(uint8_t *) pos = value; + else if (bpp <= 16) *(uint16_t *) pos = value; + else *(uint32_t *) pos = value; +} + +/* Show the state of a key on the display. */ + +static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) +{ + uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); + uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; + uint32_t bytes_per_line = fbi.bytes_per_line; + uint32_t pos; + uint32_t col, row; + + rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | + (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | + (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); + + for (row = 0; row < h; row++) + { + pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; + + for (col = 0; col < w; col++) + { + set_pixel(pos, bpp, rgb); + pos += bytes_per_pixel; + } + } +} + +/* Show the keypad status on the display. */ + +static void show_keypad(void) +{ + uint32_t colsize = fbi.width / Jz4740_keypad_gpio_outputs_count, + rowsize = fbi.height / Jz4740_keypad_gpio_inputs_count; + uint8_t column, row; + uint32_t mask; + + for (column = 0; column < Jz4740_keypad_gpio_outputs_count; column++) + + for (row = 0, mask = 1 << (Jz4740_keypad_gpio_inputs_count - 1); + row < Jz4740_keypad_gpio_inputs_count; + row++, mask >>= 1) + + show_keystate(column * colsize, row * rowsize, colsize, rowsize, + keypad[column] & mask ? 0xffffff : 0); + + /* Refresh the display. */ + + l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); +} + +int main(void) +{ + int result; + + if ((result = get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end)) < 0) + return 1; + + if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) + return 1; + + if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) + return 1; + + if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) + return 1; + + gpio_port_c = jz4740_gpio_init(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32); + gpio_port_d = jz4740_gpio_init(gpio_virt_base + 0x300, gpio_virt_base + 0x400, 32); + + init_keyscan(); + + while (1) + { + scan_keypad(); + show_keypad(); + } + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad_driver/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_keypad_driver/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,9 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_qi_lb60_keypad_driver +SRC_CC = qi_lb60_keypad_driver.cc +SRC_DATA = unifont.tff +REQUIRES_LIBS = libio l4re_c-util libdevice-input-keypad libdrivers-keypad-qi_lb60 mag-gfx + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad_driver/qi_lb60_keypad_driver.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_keypad_driver/qi_lb60_keypad_driver.cc Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,251 @@ +/* + * Access the keypad on the configured device using an input driver. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + * + * + * Font definitions and licence (see unifont.tff for bitmap data derived from + * GNU Unifont's unifont.hex file): + * + * Copyright (C) 1998-2003 Roman Czyborra (http://czyborra.com/) + * + * All glyphs are released under the GNU General Public License + * (GPL) version 2 or (at your option) a later version, with the + * GNU font embedding exception: + * + * ** GPL v2.0 license with font embedding exception: + * + * As a special exception, if you create a document which + * uses this font, and embed this font or unaltered portions + * of this font into the document, this font does not by + * itself cause the resulting document to be covered by + * the GNU General Public License. This exception does not + * however invalidate any other reasons why the document + * might be covered by the GNU General Public License. + * If you modify this font, you may extend this exception + * to your version of the font, but you are not obligated + * to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* Video abstractions. */ + +static l4re_util_video_goos_fb_t gfb; +static l4re_video_view_info_t view_info; +static void *fb = 0; + +/* Bundled font data. */ + +extern char const _binary_unifont_tff_start[]; + +/* Screen abstractions. */ + +using namespace Mag_gfx; + +static Font *_font = 0; +static Canvas *_screen = 0; + + + +/* Factories for certain pixel formats. */ + +static Mem::Factory _rgb16; +static Mem::Factory _rgb32; + + + +/* Key to character conversion function. */ + +static const char *keys_to_strings[] = { + + 0, "Escape", "1", "2", "3", "4", "5", "6", "7", "8", + + "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E", "R", + + "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Left Ctrl", + + "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", + + "'", "`", "Left Shift", "\\", "Z", "X", "C", "V", "B", "N", + + "M", ",", ".", "/", "Right Shift", "Keypad *", "Left Alt", "Space", + "Caps Lock", "F1", + + "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "Num Lock", + + "Scroll Lock", "Keypad 7", "Keypad 8", "Keypad 9", "Keypad -", "Keypad 4", + "Keypad 5", "Keypad 6", "Keypad +", "Keypad 1", + + "Keypad 2", "Keypad 3", "Keypad 0", "Keypad .", 0, 0, "#102", "F11", "F12", 0, + + 0, 0, 0, 0, 0, 0, "Keypad Enter", "Right Ctrl", "Keypad /", "SysRq", + + "Right Alt", "Line Feed", "Home", "Up", "Page Up", "Left", "Right", "End", + "Down", "Page Down", + + "Insert", "Delete", "Macro", "Mute", "Volume Down", "Volume Up", "Power", + "Keypad =", "Keypad +-", "Pause", +}; + +static const char null_string[] = "Unknown"; + +const int keys_to_strings_length = 120; + +static const char *key_to_string(int key) +{ + return key < keys_to_strings_length ? keys_to_strings[key] : 0; +} + +/* Show the keypad event status on the display. */ + +static uint8_t row = 0; +static uint32_t text_x = 0, text_y = 0, next_y = 0; + +static void handler(Input_event event, void *priv) +{ + uint32_t colsize = view_info.width / 10, + rowsize = view_info.height / 20; + uint8_t column; + uint16_t mask; + + /* Convert the key code into a bit pattern. */ + + if (!priv) + { + for (column = 0, mask = (1 << 9); column < 10; column++, mask >>= 1) + _screen->draw_box(Rect(Point(column * colsize, row * rowsize), Area(colsize, rowsize)), + event.code & mask ? event.value ? Rgb32::Color(0, 255, 0) : Rgb32::Color(255, 0, 0) + : Rgb32::Color(0, 0, 0)); + + /* Advance to the next row, wrapping around. */ + + row = (row + 1) % 20; + } + + /* Or produce a string. */ + + else if (event.value) + { + const char *s = ((const char *(*)(int)) priv)(event.code); + Rgba32::Color col; + + if (!s) + { + s = null_string; + col = Rgba32::Color(255, 0, 0, Rgba32::Color::Amax); + } + else + col = Rgba32::Color(255, 255, 255, Rgba32::Color::Amax); + + Area box = _font->str_sz(s, strlen(s)); + + /* Test for enough space horizontally. */ + + if (text_x + box.w() > view_info.width) + { + text_x = 0; + text_y = next_y; + next_y = text_y + box.h(); + } + + /* Expand the line height, if appropriate. */ + + else if (text_y + box.h() > next_y) + next_y += box.h(); + + /* Test for enough space vertically. */ + + if (next_y > view_info.height) + { + text_x = 0; + text_y = 0; + next_y = box.h(); + } + + Point p(text_x, text_y); + + _screen->draw_box(Rect(p, box), Rgb32::Color(0, 0, 0)); + _screen->draw_string(p, _font, col, s, strlen(s)); + + /* Move to the next position. */ + + text_x += box.w(); + } + + /* Refresh the display. */ + + l4re_util_video_goos_fb_refresh(&gfb, 0, 0, view_info.width, view_info.height); +} + +/* Arguments: [ chars ] */ + +int main(int argc, char *argv[]) +{ + Keypad *keypad = Keypad::get_keypad(); + Input_keypad_client client(keypad); + + if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) + return 1; + + if (l4re_util_video_goos_fb_view_info(&gfb, &view_info)) + return 1; + + if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) + return 1; + + /* Obtain a canvas for the framebuffer. */ + + Factory *factory; + + if (view_info.pixel_info.bytes_per_pixel == 2) + factory = &_rgb16; + else + factory = &_rgb32; + + Canvas *screen = factory->create_canvas((void *) ((unsigned long) fb + view_info.buffer_offset), + Area(view_info.width, view_info.height), + view_info.bytes_per_line); + + Font font(&_binary_unifont_tff_start[0]); + + _screen = screen; + _font = &font; + + /* Attach the event handler and wait for events. */ + + client.attach(handler, (argc > 1) && (!strcmp(argv[1], "chars")) ? (void *) key_to_string : 0); + + l4_sleep_forever(); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad_driver/unifont.tff Binary file pkg/landfall-examples/qi_lb60_keypad_driver/unifont.tff has changed diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad_physical/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_keypad_physical/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_qi_lb60_keypad_physical +SRC_C = qi_lb60_keypad_physical.c +REQUIRES_LIBS = l4re_c-util + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_keypad_physical/qi_lb60_keypad_physical.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_keypad_physical/qi_lb60_keypad_physical.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,308 @@ +/* + * Display the physical keypad matrix layout for the Ben NanoNote. + * + * (c) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +enum Jz4740_keypad_gpio +{ + Jz4740_keypad_gpio_inputs_count = 8, + Jz4740_keypad_gpio_outputs_count = 8, +}; + +/* Video abstractions. */ + +static l4re_util_video_goos_fb_t gfb; +static l4re_video_view_info_t fbi; +static void *fb; + +/* Keypad status and dimensions. */ + +uint32_t *keypad = 0; +void *keymem = 0; +int columns = Jz4740_keypad_gpio_outputs_count, rows = Jz4740_keypad_gpio_inputs_count; + +/* Position units. */ + +enum { + KEY = 12, DIRKEY = 8, + WIDTH = 120, HEIGHT = 72, ROWS = 6, +}; + +/* + F1 F2 F3 F4 F5 F6 F7 F8 +Q W E R T Y U I O P +A S D F G H J K L Bsp +Esc Z X C V B N M = Enter +Tab Cap \ ' , . / Up V-Up +LSh LAl Fn Sym Spc Qi Ctr Lt Dn Rt V-Dn +*/ + +enum { + SIZE_KEY_F1 = KEY, SIZE_KEY_F2 = KEY, SIZE_KEY_F3 = KEY, SIZE_KEY_F4 = KEY, + SIZE_KEY_F5 = KEY, SIZE_KEY_F6 = KEY, SIZE_KEY_F7 = KEY, SIZE_KEY_F8 = KEY, + + SIZE_KEY_Q = KEY, SIZE_KEY_W = KEY, SIZE_KEY_E = KEY, SIZE_KEY_R = KEY, + SIZE_KEY_T = KEY, SIZE_KEY_Y = KEY, SIZE_KEY_U = KEY, SIZE_KEY_I = KEY, + SIZE_KEY_O = KEY, SIZE_KEY_P = KEY, + + SIZE_KEY_A = KEY, SIZE_KEY_S = KEY, SIZE_KEY_D = KEY, SIZE_KEY_F = KEY, + SIZE_KEY_G = KEY, SIZE_KEY_H = KEY, SIZE_KEY_J = KEY, SIZE_KEY_K = KEY, + SIZE_KEY_L = KEY, SIZE_KEY_BACKSPACE = KEY, + + SIZE_KEY_ESCAPE = KEY, SIZE_KEY_Z = KEY, SIZE_KEY_X = KEY, SIZE_KEY_C = KEY, + SIZE_KEY_V = KEY, SIZE_KEY_B = KEY, SIZE_KEY_N = KEY, SIZE_KEY_M = KEY, + SIZE_KEY_EQUAL = KEY, SIZE_KEY_ENTER = KEY, + + SIZE_KEY_TAB = KEY, SIZE_KEY_DOWNSHIFT = KEY, SIZE_KEY_BACKSLASH = KEY, SIZE_KEY_APOSTROPHE = KEY, + SIZE_KEY_COMMA = KEY, SIZE_KEY_DOT = KEY, SIZE_KEY_SLASH = KEY, + SIZE_KEY_UP = DIRKEY, SIZE_KEY_VOLUMEUP = KEY, + + SIZE_KEY_LEFTSHIFT = KEY, SIZE_KEY_LEFTALT = KEY, SIZE_KEY_FN = KEY, SIZE_KEY_SYM = KEY, + SIZE_KEY_SPACE = KEY, SIZE_KEY_QI = KEY, SIZE_KEY_RIGHTCTRL = KEY, SIZE_KEY_LEFT = DIRKEY, + SIZE_KEY_DOWN = DIRKEY, SIZE_KEY_RIGHT = DIRKEY, SIZE_KEY_VOLUMEDOWN = KEY, +}; + +enum { + XPOS_KEY_F1 = 2*KEY, XPOS_KEY_F2 = 3*KEY, XPOS_KEY_F3 = 4*KEY, XPOS_KEY_F4 = 5*KEY, + XPOS_KEY_F5 = 6*KEY, XPOS_KEY_F6 = 7*KEY, XPOS_KEY_F7 = 8*KEY, XPOS_KEY_F8 = 9*KEY, + + XPOS_KEY_Q = 0, XPOS_KEY_W = KEY, XPOS_KEY_E = 2*KEY, XPOS_KEY_R = 3*KEY, + XPOS_KEY_T = 4*KEY, XPOS_KEY_Y = 5*KEY, XPOS_KEY_U = 6*KEY, XPOS_KEY_I = 7*KEY, + XPOS_KEY_O = 8*KEY, XPOS_KEY_P = 9*KEY, + + XPOS_KEY_A = 0, XPOS_KEY_S = KEY, XPOS_KEY_D = 2*KEY, XPOS_KEY_F = 3*KEY, + XPOS_KEY_G = 4*KEY, XPOS_KEY_H = 5*KEY, XPOS_KEY_J = 6*KEY, XPOS_KEY_K = 7*KEY, + XPOS_KEY_L = 8*KEY, XPOS_KEY_BACKSPACE = 9*KEY, + + XPOS_KEY_ESCAPE = 0, XPOS_KEY_Z = KEY, XPOS_KEY_X = 2*KEY, XPOS_KEY_C = 3*KEY, + XPOS_KEY_V = 4*KEY, XPOS_KEY_B = 5*KEY, XPOS_KEY_N = 6*KEY, XPOS_KEY_M = 7*KEY, + XPOS_KEY_EQUAL = 8*KEY, XPOS_KEY_ENTER = 9*KEY, + + XPOS_KEY_TAB = 0, XPOS_KEY_DOWNSHIFT = KEY, XPOS_KEY_BACKSLASH = 2*KEY, XPOS_KEY_APOSTROPHE = 3*KEY, + XPOS_KEY_COMMA = 4*KEY, XPOS_KEY_DOT = 5*KEY, XPOS_KEY_SLASH = 6*KEY, + XPOS_KEY_UP = 7*KEY+DIRKEY, XPOS_KEY_VOLUMEUP = 9*KEY, + + XPOS_KEY_LEFTSHIFT = 0, XPOS_KEY_LEFTALT = KEY, XPOS_KEY_FN = 2*KEY, XPOS_KEY_SYM = 3*KEY, + XPOS_KEY_SPACE = 4*KEY, XPOS_KEY_QI = 5*KEY, XPOS_KEY_RIGHTCTRL = 6*KEY, XPOS_KEY_LEFT = 7*KEY, + XPOS_KEY_DOWN = 7*KEY+DIRKEY, XPOS_KEY_RIGHT = 7*KEY+2*DIRKEY, XPOS_KEY_VOLUMEDOWN = 9*KEY, +}; + +enum { + YPOS_KEY_F1 = 0, YPOS_KEY_F2 = 0, YPOS_KEY_F3 = 0, YPOS_KEY_F4 = 0, + YPOS_KEY_F5 = 0, YPOS_KEY_F6 = 0, YPOS_KEY_F7 = 0, YPOS_KEY_F8 = 0, + + YPOS_KEY_Q = 1, YPOS_KEY_W = 1, YPOS_KEY_E = 1, YPOS_KEY_R = 1, + YPOS_KEY_T = 1, YPOS_KEY_Y = 1, YPOS_KEY_U = 1, YPOS_KEY_I = 1, + YPOS_KEY_O = 1, YPOS_KEY_P = 1, + + YPOS_KEY_A = 2, YPOS_KEY_S = 2, YPOS_KEY_D = 2, YPOS_KEY_F = 2, + YPOS_KEY_G = 2, YPOS_KEY_H = 2, YPOS_KEY_J = 2, YPOS_KEY_K = 2, + YPOS_KEY_L = 2, YPOS_KEY_BACKSPACE = 2, + + YPOS_KEY_ESCAPE = 3, YPOS_KEY_Z = 3, YPOS_KEY_X = 3, YPOS_KEY_C = 3, + YPOS_KEY_V = 3, YPOS_KEY_B = 3, YPOS_KEY_N = 3, YPOS_KEY_M = 3, + YPOS_KEY_EQUAL = 3, YPOS_KEY_ENTER = 3, + + YPOS_KEY_TAB = 4, YPOS_KEY_DOWNSHIFT = 4, YPOS_KEY_BACKSLASH = 4, YPOS_KEY_APOSTROPHE = 4, + YPOS_KEY_COMMA = 4, YPOS_KEY_DOT = 4, YPOS_KEY_SLASH = 4, + YPOS_KEY_UP = 4, YPOS_KEY_VOLUMEUP = 4, + + YPOS_KEY_LEFTSHIFT = 5, YPOS_KEY_LEFTALT = 5, YPOS_KEY_FN = 5, YPOS_KEY_SYM = 5, + YPOS_KEY_SPACE = 5, YPOS_KEY_QI = 5, YPOS_KEY_RIGHTCTRL = 5, YPOS_KEY_LEFT = 5, + YPOS_KEY_DOWN = 5, YPOS_KEY_RIGHT = 5, YPOS_KEY_VOLUMEDOWN = 5, +}; + +/* Keypad matrix mapping. */ + +#define PHYS_KEY(X) {XPOS_KEY_##X, YPOS_KEY_##X, SIZE_KEY_##X} +#define PHYS_NULL {0, 0, 0} + +static const uint32_t keypos[Jz4740_keypad_gpio_inputs_count][Jz4740_keypad_gpio_outputs_count][3] = { + +{PHYS_KEY(F1), PHYS_KEY(F2), PHYS_KEY(F3), PHYS_KEY(F4), PHYS_KEY(F5), PHYS_KEY(F6), + PHYS_KEY(F7), PHYS_NULL}, + +{PHYS_KEY(Q), PHYS_KEY(W), PHYS_KEY(E), PHYS_KEY(R), PHYS_KEY(T), PHYS_KEY(Y), + PHYS_KEY(U), PHYS_KEY(I)}, + +{PHYS_KEY(A), PHYS_KEY(S), PHYS_KEY(D), PHYS_KEY(F), PHYS_KEY(G), PHYS_KEY(H), + PHYS_KEY(J), PHYS_KEY(K)}, + +{PHYS_KEY(ESCAPE), PHYS_KEY(Z), PHYS_KEY(X), PHYS_KEY(C), PHYS_KEY(V), PHYS_KEY(B), + PHYS_KEY(N), PHYS_KEY(M)}, + +{PHYS_KEY(TAB), PHYS_KEY(DOWNSHIFT) /* CAPSLOCK */, PHYS_KEY(BACKSLASH), + PHYS_KEY(APOSTROPHE), PHYS_KEY(COMMA), PHYS_KEY(DOT), PHYS_KEY(SLASH), PHYS_KEY(UP)}, + +{PHYS_KEY(O), PHYS_KEY(L), PHYS_KEY(EQUAL), PHYS_KEY(SYM) /* RIGHTALT */, + PHYS_KEY(SPACE), PHYS_KEY(QI) /* F13 */, PHYS_KEY(RIGHTCTRL), PHYS_KEY(LEFT)}, + +{PHYS_KEY(F8), PHYS_KEY(P), PHYS_KEY(BACKSPACE), PHYS_KEY(ENTER), PHYS_KEY(VOLUMEUP), + PHYS_KEY(VOLUMEDOWN), PHYS_KEY(DOWN), PHYS_KEY(RIGHT)}, + +{PHYS_KEY(LEFTSHIFT), PHYS_KEY(LEFTALT), PHYS_KEY(FN), PHYS_NULL, PHYS_NULL, + PHYS_NULL, PHYS_NULL, PHYS_NULL} +}; + + + +static uint32_t bitmask(uint32_t size) +{ + return (1 << size) - 1; +} + +static uint32_t truncate_channel(uint32_t value, uint32_t size) +{ + return (value >> (8 - size)) & bitmask(size); +} + +static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) +{ + if (bpp <= 8) *(uint8_t *) pos = value; + else if (bpp <= 16) *(uint16_t *) pos = value; + else *(uint32_t *) pos = value; +} + +/* Show the state of a key on the display. */ + +static void fill_rectangle(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) +{ + uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); + uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; + uint32_t bytes_per_line = fbi.bytes_per_line; + uint32_t pos; + uint32_t col, row; + + rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | + (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | + (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); + + for (row = 0; row < h; row++) + { + pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; + + for (col = 0; col < w; col++) + { + set_pixel(pos, bpp, rgb); + pos += bytes_per_pixel; + } + } +} + +/* Show the keypad status on the display. */ + +static void show_keypad(void) +{ + uint32_t rowsize = fbi.height / ROWS, colsize; + uint8_t column, row; + uint32_t mask; + const uint32_t *pos; + + for (column = 0; column < columns; column++) + + for (row = 0, mask = 1 << (rows - 1); + row < rows; + row++, mask >>= 1) + { + /* Obtain the physical position. */ + + pos = keypos[row][column]; + + /* Obtain the width of the key. */ + + colsize = (pos[2] * fbi.width) / WIDTH; + + /* Plot the rectangle for the key. */ + + fill_rectangle((pos[0] * fbi.width) / WIDTH, pos[1] * rowsize, colsize, rowsize, + keypad[column] & mask ? 0xffffff : 0); + } + + /* Refresh the display. */ + + l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); +} + + + +int main(void) +{ + l4_cap_idx_t keypad_server; + l4re_ds_t mem; + l4_msgtag_t tag; + + if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) + return 1; + + if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) + return 1; + + if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) + return 1; + + /* Obtain a reference to the keypad. */ + + keypad_server = l4re_env_get_cap("keypad"); + if (l4_is_invalid_cap(keypad_server)) return 1; + + /* Obtain a capability for the keypad data. */ + + mem = l4re_util_cap_alloc(); + if (l4_is_invalid_cap(mem)) return 1; + + /* Obtain a reference to the keypad data. */ + + l4_utcb_br()->bdr = 0; + l4_utcb_br()->br[0] = L4_RCV_ITEM_SINGLE_CAP | mem; + + tag = l4_ipc_call(keypad_server, l4_utcb(), + l4_msgtag(0, 0, 0, 0), /* label zero, zero words, zero *sent* items */ + L4_IPC_NEVER); + + if (l4_ipc_error(tag, l4_utcb())) return 1; + + /* Attach the keypad data to a region in this task. */ + + if (l4re_rm_attach(&keymem, l4re_ds_size(mem), L4RE_RM_SEARCH_ADDR, mem, 0, + L4_PAGESHIFT)) + return 1; + + /* Show the keypad state. */ + + keypad = (uint32_t *) keymem; + + while (1) show_keypad(); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/Makefile Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = ex_qi_lb60_lcd +SRC_C = qi_lb60_lcd.c jzlcd.c nanonote_gpm940b0.c memory.c +REQUIRES_LIBS = libio l4re_c-util libdrivers-cpm libdrivers-gpio + +include $(L4DIR)/mk/prog.mk diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/jzlcd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/jzlcd.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,565 @@ +/* + * jz4740 LCD controller configuration. + * + * Copyright (C) Xiangfu Liu + * Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "jzlcd.h" +#include "xburst_types.h" /* for REG32 */ +#include /* for l4_cache functions */ + +/* Useful alignment operations. */ + +static inline void align2(uint32_t *n) +{ + *n = (((*n)+1)>>1)<<1; +} + +static inline void align4(uint32_t *n) +{ + *n = (((*n)+3)>>2)<<2; +} + +static inline void align8(uint32_t *n) +{ + *n = (((*n)+7)>>3)<<3; +} + + + +/* Register operations. */ + +static inline uint32_t lcd_ctrl_get(vidinfo_t *vid, uint32_t reg) +{ + return REG32(vid->lcd + reg); +} + +static inline void lcd_ctrl_set(vidinfo_t *vid, uint32_t reg, uint32_t value) +{ + REG32(vid->lcd + reg) = value; +} + + + +/* Configuration operations. */ + +/* Return the number of panels available. */ + +static uint8_t lcd_get_panels(vidinfo_t *vid) +{ + struct jzfb_info *jzfb = vid->jz_fb; + uint32_t mode = jzfb->cfg & MODE_MASK; + + return (mode == MODE_STN_MONO_DUAL) || + (mode == MODE_STN_COLOR_DUAL) ? 2 : 1; +} + +/* Calculate and return the pixel clock frequency. */ + +static uint32_t lcd_get_pixel_clock(vidinfo_t *vid) +{ + struct jzfb_info *jzfb = vid->jz_fb; + uint32_t pclk, width_cycles, mode = jzfb->cfg & MODE_MASK; + + /* + Serial mode: 3 pixel clock cycles per pixel (one per channel). + Parallel mode: 1 pixel clock cycle per pixel. + */ + + if (mode == MODE_8BIT_SERIAL_TFT) + width_cycles = jzfb->w * 3; + else + width_cycles = jzfb->w; + + /* Derive pixel clock from frame clock. */ + + pclk = jzfb->fclk * + (width_cycles + jzfb->hsw + jzfb->elw + jzfb->blw) * + (jzfb->h + jzfb->vsw + jzfb->efw + jzfb->bfw); + + if ((mode == MODE_STN_COLOR_SINGLE) || (mode == MODE_STN_COLOR_DUAL)) + pclk = (pclk * 3); + + if ((mode == MODE_STN_COLOR_SINGLE) || (mode == MODE_STN_COLOR_DUAL) || + (mode == MODE_STN_MONO_SINGLE) || (mode == MODE_STN_MONO_DUAL)) + pclk = pclk >> ((jzfb->cfg & STN_DAT_PINMASK) >> 4); + + if ((mode == MODE_STN_COLOR_DUAL) || (mode == MODE_STN_MONO_DUAL)) + pclk >>= 1; + + return pclk; +} + + + +/* Functions returning region sizes. */ + +static uint32_t lcd_get_line_size(vidinfo_t *vid) +{ + /* Lines must be aligned to a word boundary. */ + + return ALIGN((vid->jz_fb->w * vid->jz_fb->bpp) / 8, sizeof(uint32_t)); +} + +static uint32_t lcd_get_size(vidinfo_t *vid) +{ + return lcd_get_line_size(vid) * vid->jz_fb->h; +} + +static uint32_t lcd_get_aligned_size(vidinfo_t *vid) +{ + /* LCD_CTRL_BST_16 requires 16-word alignment. */ + + return ALIGN(lcd_get_size(vid), 16 * sizeof(uint32_t)); +} + +static uint32_t lcd_get_palette_size(vidinfo_t *vid) +{ + /* Get a collection of two-byte entries, one per colour. */ + + if (vid->jz_fb->bpp < 12) + return (1 << (vid->jz_fb->bpp)) * sizeof(uint16_t); + else + return 0; +} + +static uint32_t lcd_get_aligned_palette_size(vidinfo_t *vid) +{ + /* LCD_CTRL_BST_16 requires 16-word alignment. */ + + return ALIGN(lcd_get_palette_size(vid), 16 * sizeof(uint32_t)); +} + +static uint32_t lcd_get_descriptors_size(vidinfo_t *vid) +{ + return 3 * sizeof(struct jz_fb_dma_descriptor); +} + + + +/* Functions returning addresses of each data region. +The screen parameter permits the retrieval of virtual or physical addresses. */ + +static uint32_t lcd_get_palette(vidinfo_t *vid, uint32_t screen) +{ + /* Use memory at the end of the allocated region for the palette. */ + + return screen + jz4740_lcd_get_screen_size(vid) - lcd_get_aligned_palette_size(vid); +} + +static uint32_t lcd_get_framebuffer(uint8_t panel, vidinfo_t *vid, uint32_t screen) +{ + /* Framebuffers for panels are allocated at the start of the region. */ + + return screen + (panel * lcd_get_aligned_size(vid)); +} + + + +/* Initialisation functions. */ + +static uint32_t jz_lcd_stn_init(uint32_t stnH, vidinfo_t *vid) +{ + struct jzfb_info *jzfb = vid->jz_fb; + uint32_t val = 0; + + switch (jzfb->bpp) { + case 1: + /* val |= LCD_CTRL_PEDN; */ + case 2: + val |= LCD_CTRL_FRC_2; + break; + + case 4: + val |= LCD_CTRL_FRC_4; + break; + + case 8: + default: + val |= LCD_CTRL_FRC_16; + break; + } + + switch (jzfb->cfg & STN_DAT_PINMASK) { + case STN_DAT_PIN1: + /* Do not adjust the hori-param value. */ + break; + + case STN_DAT_PIN2: + align2(&jzfb->hsw); + align2(&jzfb->elw); + align2(&jzfb->blw); + break; + + case STN_DAT_PIN4: + align4(&jzfb->hsw); + align4(&jzfb->elw); + align4(&jzfb->blw); + break; + + case STN_DAT_PIN8: + align8(&jzfb->hsw); + align8(&jzfb->elw); + align8(&jzfb->blw); + break; + } + + lcd_ctrl_set(vid, LCD_VSYNC, jzfb->vsw); + lcd_ctrl_set(vid, LCD_HSYNC, ((jzfb->blw + jzfb->w) << 16) | (jzfb->blw + jzfb->w + jzfb->hsw)); + + /* Screen setting */ + lcd_ctrl_set(vid, LCD_VAT, ((jzfb->blw + jzfb->w + jzfb->hsw + jzfb->elw) << 16) | (stnH + jzfb->vsw + jzfb->bfw + jzfb->efw)); + lcd_ctrl_set(vid, LCD_DAH, (jzfb->blw << 16) | (jzfb->blw + jzfb->w)); + lcd_ctrl_set(vid, LCD_DAV, stnH); + + /* AC BIAs signal */ + lcd_ctrl_set(vid, LCD_PS, stnH+jzfb->vsw+jzfb->efw+jzfb->bfw); + + return val; +} + +static void jz_lcd_tft_init(vidinfo_t *vid) +{ + struct jzfb_info *jzfb = vid->jz_fb; + + lcd_ctrl_set(vid, LCD_VSYNC, jzfb->vsw); + lcd_ctrl_set(vid, LCD_HSYNC, jzfb->hsw); + lcd_ctrl_set(vid, LCD_DAV, ((jzfb->vsw + jzfb->bfw) << 16) | (jzfb->vsw + jzfb->bfw + jzfb->h)); + lcd_ctrl_set(vid, LCD_DAH, ((jzfb->hsw + jzfb->blw) << 16) | (jzfb->hsw + jzfb->blw + jzfb->w)); + lcd_ctrl_set(vid, LCD_VAT, (((jzfb->blw + jzfb->w + jzfb->elw + jzfb->hsw)) << 16) | + (jzfb->vsw + jzfb->bfw + jzfb->h + jzfb->efw)); +} + +static void jz_lcd_samsung_init(vidinfo_t *vid) +{ + struct jzfb_info *jzfb = vid->jz_fb; + uint32_t pclk = lcd_get_pixel_clock(vid); + uint32_t total, tp_s, tp_e, ckv_s, ckv_e; + uint32_t rev_s, rev_e, inv_s, inv_e; + + jz_lcd_tft_init(vid); + + total = jzfb->blw + jzfb->w + jzfb->elw + jzfb->hsw; + tp_s = jzfb->blw + jzfb->w + 1; + tp_e = tp_s + 1; + /* ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100); */ + ckv_s = tp_s - pclk/(1000000000/4100); + ckv_e = tp_s + total; + rev_s = tp_s - 11; /* -11.5 clk */ + rev_e = rev_s + total; + inv_s = tp_s; + inv_e = inv_s + total; + lcd_ctrl_set(vid, LCD_CLS, (tp_s << 16) | tp_e); + lcd_ctrl_set(vid, LCD_PS, (ckv_s << 16) | ckv_e); + lcd_ctrl_set(vid, LCD_SPL, (rev_s << 16) | rev_e); + lcd_ctrl_set(vid, LCD_REV, (inv_s << 16) | inv_e); + jzfb->cfg |= STFT_REVHI | STFT_SPLHI; +} + +static void jz_lcd_sharp_init(vidinfo_t *vid) +{ + struct jzfb_info *jzfb = vid->jz_fb; + uint32_t total, cls_s, cls_e, ps_s, ps_e; + uint32_t spl_s, spl_e, rev_s, rev_e; + + jz_lcd_tft_init(vid); + + total = jzfb->blw + jzfb->w + jzfb->elw + jzfb->hsw; + spl_s = 1; + spl_e = spl_s + 1; + cls_s = 0; + cls_e = total - 60; /* > 4us (pclk = 80ns) */ + ps_s = cls_s; + ps_e = cls_e; + rev_s = total - 40; /* > 3us (pclk = 80ns) */ + rev_e = rev_s + total; + jzfb->cfg |= STFT_PSHI; + lcd_ctrl_set(vid, LCD_SPL, (spl_s << 16) | spl_e); + lcd_ctrl_set(vid, LCD_CLS, (cls_s << 16) | cls_e); + lcd_ctrl_set(vid, LCD_PS, (ps_s << 16) | ps_e); + lcd_ctrl_set(vid, LCD_REV, (rev_s << 16) | rev_e); +} + + + +/* Palette initialisation. */ + +static inline uint16_t rgb8_to_rgb16(uint8_t rgb) +{ + return ((((rgb & 0xe0) >> 5) * 4) << 11) | ((((rgb & 0x1c) >> 2) * 9) << 6) | ((rgb & 0x03) * 10); +} + +static inline uint16_t rgb4_to_rgb16(uint8_t rgb) +{ + return ((((rgb & 8) >> 3) * 0x1f) << 11) | ((((rgb & 6) >> 1) * 0x15) << 5) | ((rgb & 1) * 0x1f); +} + +static void lcd_init_palette(vidinfo_t *vid, uint32_t palette) +{ + uint16_t *entry = (uint16_t *) palette; + uint16_t *end = entry + (1 << (vid->jz_fb->bpp)); + uint8_t value = 0; + + while (entry < end) + { + switch (vid->jz_fb->bpp) + { + case 4: + *entry = rgb4_to_rgb16(value); + break; + + case 8: + default: + *entry = rgb8_to_rgb16(value); + break; + } + + value++; + entry++; + } +} + + + +/* Public functions. */ + +uint32_t jz4740_lcd_get_aligned_size(vidinfo_t *vid) +{ + return lcd_get_aligned_size(vid); +} + +uint32_t jz4740_lcd_get_descriptors_size(vidinfo_t *vid) +{ + return lcd_get_descriptors_size(vid); +} + +uint32_t jz4740_lcd_get_line_size(vidinfo_t *vid) +{ + return lcd_get_line_size(vid); +} + +/* Return the total size of the required memory. */ + +uint32_t jz4740_lcd_get_screen_size(vidinfo_t *vid) +{ + return lcd_get_aligned_size(vid) * lcd_get_panels(vid) + + lcd_get_aligned_palette_size(vid); +} + +/* Return the calculated pixel clock frequency for the display. */ + +uint32_t jz4740_lcd_get_pixel_clock(vidinfo_t *vid) +{ + return lcd_get_pixel_clock(vid); +} + +/* Set the LCD controller address. */ + +void jz4740_lcd_set_base(vidinfo_t *vid, void *lcd_base) +{ + vid->lcd = lcd_base; +} + +/* Initialise the LCD controller with the memory, panel and framebuffer details. */ + +void jz4740_lcd_ctrl_init( + struct jz_fb_dma_descriptor *desc_vaddr, + struct jz_fb_dma_descriptor *desc_paddr, + void *fb_vaddr, void *fb_paddr, + vidinfo_t *vid) +{ + struct jz_fb_dma_descriptor *first, *second = 0; + + /* Initialise a palette for lower colour depths. */ + + if (vid->jz_fb->bpp < 12) + lcd_init_palette(vid, lcd_get_palette(vid, (uint32_t) fb_vaddr)); + + /* Populate descriptors. */ + + /* Provide the first framebuffer descriptor in single and dual modes. */ + + desc_vaddr[0].fsadr = lcd_get_framebuffer(0, vid, (uint32_t) fb_paddr); + desc_vaddr[0].fidr = 0; + desc_vaddr[0].ldcmd = lcd_get_size(vid) / 4; /* length in words */ + + /* Provide the second framebuffer descriptor only in dual-panel mode. */ + + if (lcd_get_panels(vid) == 2) + { + desc_vaddr[1].fdadr = desc_paddr + 1; + desc_vaddr[1].fsadr = lcd_get_framebuffer(1, vid, (uint32_t) fb_paddr); + desc_vaddr[1].fidr = 0; + desc_vaddr[1].ldcmd = lcd_get_size(vid) / 4; + + /* Note the address to be provided for the second channel. */ + + second = desc_paddr + 1; + } + + /* Initialise palette descriptor details if a palette is to be used. */ + + /* Assume any mode with <12 bpp is palette driven. */ + + if (vid->jz_fb->bpp < 12) + { + desc_vaddr[2].fsadr = lcd_get_palette(vid, (uint32_t) fb_paddr); + desc_vaddr[2].fidr = 0; + desc_vaddr[2].ldcmd = (lcd_get_palette_size(vid) / 4) | LCD_CMD_PAL; + + /* Flip back and forth between the palette and framebuffer. */ + + desc_vaddr[2].fdadr = desc_paddr; + desc_vaddr[0].fdadr = desc_paddr + 2; + + /* Provide the palette descriptor address first. */ + + first = desc_paddr + 2; + } + else + { + /* No palette: always use the framebuffer descriptor. */ + + desc_vaddr[0].fdadr = desc_paddr; + first = desc_paddr; + } + + /* Flush cached structure data. */ + + l4_cache_clean_data((unsigned long) desc_vaddr, + (unsigned long) desc_vaddr + lcd_get_descriptors_size(vid)); + + /* Configure DMA by setting frame descriptor addresses. */ + + lcd_ctrl_set(vid, LCD_DA0, (uint32_t) first); + + if (lcd_get_panels(vid) == 2) + lcd_ctrl_set(vid, LCD_DA1, (uint32_t) second); +} + +/* Initialise the LCD registers. */ + +void jz4740_lcd_hw_init(vidinfo_t *vid) +{ + struct jzfb_info *jzfb = vid->jz_fb; + uint32_t mode = vid->jz_fb->cfg & MODE_MASK; + uint32_t val = 0; + + /* Compute control register flags. */ + + switch (jzfb->bpp) { + case 1: + val |= LCD_CTRL_BPP_1; + break; + + case 2: + val |= LCD_CTRL_BPP_2; + break; + + case 4: + val |= LCD_CTRL_BPP_4; + break; + + case 8: + val |= LCD_CTRL_BPP_8; + break; + + case 15: + val |= LCD_CTRL_RGB555; + case 16: + val |= LCD_CTRL_BPP_16; + break; + + case 17 ... 32: + val |= LCD_CTRL_BPP_18_24; /* target is 4bytes/pixel */ + break; + + default: + val |= LCD_CTRL_BPP_16; /* default to 16bpp */ + break; + } + + /* Set various configuration registers for the panel. */ + + switch (mode) { + case MODE_STN_MONO_DUAL: + case MODE_STN_COLOR_DUAL: + val |= jz_lcd_stn_init(jzfb->h >> 1, vid); + break; + + case MODE_STN_MONO_SINGLE: + case MODE_STN_COLOR_SINGLE: + val |= jz_lcd_stn_init(jzfb->h, vid); + break; + + case MODE_TFT_GEN: + case MODE_TFT_CASIO: + case MODE_8BIT_SERIAL_TFT: + case MODE_TFT_18BIT: + jz_lcd_tft_init(vid); + break; + + case MODE_TFT_SAMSUNG: + jz_lcd_samsung_init(vid); + break; + + case MODE_TFT_SHARP: + jz_lcd_sharp_init(vid); + break; + + default: + break; + } + + /* Further control register and panel configuration. */ + + val |= LCD_CTRL_BST_16; /* Burst Length is 16WORD=64Byte */ + val |= LCD_CTRL_OFUP; /* OutFIFO underrun protect */ + + lcd_ctrl_set(vid, LCD_CTRL, val); + lcd_ctrl_set(vid, LCD_CFG, jzfb->cfg); +} + +/* Set the colour depth. */ + +void jz4740_lcd_set_bpp(uint8_t bpp, vidinfo_t *vid) +{ + vid->jz_fb->bpp = bpp; +} + +void jz4740_lcd_enable(vidinfo_t *vid) +{ + /* Clear the disable bit (DIS) and set the enable bit (ENA). */ + + lcd_ctrl_set(vid, LCD_CTRL, (lcd_ctrl_get(vid, LCD_CTRL) & ~LCD_CTRL_DIS) | LCD_CTRL_ENA); +} + +void jz4740_lcd_disable(vidinfo_t *vid) +{ + /* Set the disable bit (DIS). */ + + lcd_ctrl_set(vid, LCD_CTRL, lcd_ctrl_get(vid, LCD_CTRL) | LCD_CTRL_DIS); +} + +void jz4740_lcd_quick_disable(vidinfo_t *vid) +{ + /* Clear the enable bit (ENA) for quick disable. */ + + lcd_ctrl_set(vid, LCD_CTRL, lcd_ctrl_get(vid, LCD_CTRL) & ~LCD_CTRL_ENA); +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/jzlcd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/jzlcd.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,236 @@ +/* + * U-Boot and jz4740 LCD controller definitions. + * + * Copyright (C) 2001 Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. + * Copyright (C) 2009 Qi Hardware Inc. + * Author: Xiangfu Liu + * Copyright (C) Xiangfu Liu + * Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#ifndef __JZLCD_H__ +#define __JZLCD_H__ + +#include + +/* Framebuffer characteristics. */ + +struct jzfb_info { + uint32_t cfg; /* panel mode and pin usage etc. */ + uint32_t w; /* display width in pixels */ + uint32_t h; /* display height in pixels */ + uint32_t bpp; /* bits per pixel */ + uint32_t fclk; /* frame clock */ + uint32_t hsw; /* hsync width, in pixel clock */ + uint32_t vsw; /* vsync width, in line count */ + uint32_t elw; /* end of line, in pixel clock */ + uint32_t blw; /* begin of line, in pixel clock */ + uint32_t efw; /* end of frame, in line count */ + uint32_t bfw; /* begin of frame, in line count */ +}; + +/* LCD controller stucture for jz4740. */ + +struct jz_fb_dma_descriptor { + struct jz_fb_dma_descriptor *fdadr; /* frame descriptor address register */ + uint32_t fsadr; /* frame source address register */ + uint32_t fidr; /* frame identifier register */ + uint32_t ldcmd; /* command register */ +}; + +/* Display characteristics and memory resources. */ + +typedef struct vidinfo { + struct jzfb_info *jz_fb; /* framebuffer and panel properties */ + void *lcd; /* address of LCD controller registers */ +} vidinfo_t; + + + +/* Public functions. */ + +uint32_t jz4740_lcd_get_aligned_size(vidinfo_t *vid); +uint32_t jz4740_lcd_get_descriptors_size(vidinfo_t *vid); +uint32_t jz4740_lcd_get_line_size(vidinfo_t *vid); +uint32_t jz4740_lcd_get_screen_size(vidinfo_t *vid); +uint32_t jz4740_lcd_get_pixel_clock(vidinfo_t *vid); + +void jz4740_lcd_set_base(vidinfo_t *vid, void *lcd_base); + +void jz4740_lcd_ctrl_init( + struct jz_fb_dma_descriptor *desc_vaddr, + struct jz_fb_dma_descriptor *desc_paddr, + void *fb_vaddr, void *fb_paddr, + vidinfo_t *vid); + +void jz4740_lcd_hw_init(vidinfo_t *vid); +void jz4740_lcd_set_bpp(uint8_t bpp, vidinfo_t *vid); +void jz4740_lcd_enable(vidinfo_t *vid); +void jz4740_lcd_disable(vidinfo_t *vid); +void jz4740_lcd_quick_disable(vidinfo_t *vid); + + + +/* Alignment/rounding macros. */ + +#define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) + +/* Display device mode select (LCD_CFG.MODE). */ + +#define MODE_MASK 0x0f +#define MODE_TFT_GEN 0x00 +#define MODE_TFT_SHARP 0x01 +#define MODE_TFT_CASIO 0x02 +#define MODE_TFT_SAMSUNG 0x03 +#define MODE_CCIR656_NONINT 0x04 +#define MODE_CCIR656_INT 0x05 +#define MODE_STN_COLOR_SINGLE 0x08 +#define MODE_STN_MONO_SINGLE 0x09 +#define MODE_STN_COLOR_DUAL 0x0a +#define MODE_STN_MONO_DUAL 0x0b +#define MODE_8BIT_SERIAL_TFT 0x0c + +/* 16-bit or 18-bit TFT panel selection (LCD_CFG.18/16). */ + +#define MODE_TFT_18BIT (1<<7) + +/* STN pin utilisation (LCD_CFG.PDW). */ + +#define STN_DAT_PIN1 (0x00 << 4) +#define STN_DAT_PIN2 (0x01 << 4) +#define STN_DAT_PIN4 (0x02 << 4) +#define STN_DAT_PIN8 (0x03 << 4) +#define STN_DAT_PINMASK STN_DAT_PIN8 + +/* Pin reset states (LCD_CFG). */ + +#define STFT_PSHI (1 << 15) +#define STFT_CLSHI (1 << 14) +#define STFT_SPLHI (1 << 13) +#define STFT_REVHI (1 << 12) + +/* Sync direction (LCD_CFG.SYNDIR). */ + +#define SYNC_MASTER (0 << 16) +#define SYNC_SLAVE (1 << 16) + +/* Data enable polarity (LCD_CFG.DEP). */ + +#define DE_P (0 << 9) +#define DE_N (1 << 9) + +/* Pixel clock polarity (LCD_CFG.PCP). */ + +#define PCLK_P (0 << 10) +#define PCLK_N (1 << 10) + +/* Horizontal sync polarity (LCD_CFG.HSP). */ + +#define HSYNC_P (0 << 11) +#define HSYNC_N (1 << 11) + +/* Vertical sync polarity (LCD_CFG.VSP). */ + +#define VSYNC_P (0 << 8) +#define VSYNC_N (1 << 8) + +/* Inverse output data (LCD_CFG.INVDAT). */ + +#define DATA_NORMAL (0 << 17) +#define DATA_INVERSE (1 << 17) + +/* Register offsets. */ + +#define LCD_CFG 0x00 /* LCD Configure Register */ +#define LCD_VSYNC 0x04 /* Vertical Synchronize Register */ +#define LCD_HSYNC 0x08 /* Horizontal Synchronize Register */ +#define LCD_VAT 0x0c /* Virtual Area Setting Register */ +#define LCD_DAH 0x10 /* Display Area Horizontal Start/End Point */ +#define LCD_DAV 0x14 /* Display Area Vertical Start/End Point */ +#define LCD_PS 0x18 /* PS Signal Setting */ +#define LCD_CLS 0x1c /* CLS Signal Setting */ +#define LCD_SPL 0x20 /* SPL Signal Setting */ +#define LCD_REV 0x24 /* REV Signal Setting */ +#define LCD_CTRL 0x30 /* LCD Control Register */ +#define LCD_STATE 0x34 /* LCD Status Register */ +#define LCD_IID 0x38 /* Interrupt ID Register */ +#define LCD_DA0 0x40 /* Descriptor Address Register 0 */ +#define LCD_SA0 0x44 /* Source Address Register 0 */ +#define LCD_FID0 0x48 /* Frame ID Register 0 */ +#define LCD_CMD0 0x4c /* DMA Command Register 0 */ +#define LCD_DA1 0x50 /* Descriptor Address Register 1 */ +#define LCD_SA1 0x54 /* Source Address Register 1 */ +#define LCD_FID1 0x58 /* Frame ID Register 1 */ +#define LCD_CMD1 0x5c /* DMA Command Register 1 */ + +/* Burst length selection (LCD_CTRL.BST). */ + +#define LCD_CTRL_BST_MASK (0x03 << 28) +#define LCD_CTRL_BST_4 (0 << 28) /* 4-word */ +#define LCD_CTRL_BST_8 (1 << 28) /* 8-word */ +#define LCD_CTRL_BST_16 (2 << 28) /* 16-word */ + +/* RGB mode (LCD_CTRL.RGB). */ + +#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode */ +#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode */ + +/* Output FIFO underrun protection (LCD_CTRL.OFUP). */ + +#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ + +/* STN FRC algorithm selection (LCD_CTRL.FRC). */ + +#define LCD_CTRL_FRC_16 (0 << 24) /* 16 grayscale */ +#define LCD_CTRL_FRC_4 (1 << 24) /* 4 grayscale */ +#define LCD_CTRL_FRC_2 (2 << 24) /* 2 grayscale */ +#define LCD_CTRL_FRC_MASK (0x03 << 24) + +/* Load palette delay counter (LCD_CTRL.PDD) */ + +#define LCD_CTRL_PDD_MASK (0xff << 16) + +#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ +#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ +#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ +#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ +#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ +#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ +#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ +#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ +#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ +#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ +#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ + +/* Bits per pixel (LCD_CTRL.BPP). */ + +#define LCD_CTRL_BPP_1 0 /* 1 bpp */ +#define LCD_CTRL_BPP_2 1 /* 2 bpp */ +#define LCD_CTRL_BPP_4 2 /* 4 bpp */ +#define LCD_CTRL_BPP_8 3 /* 8 bpp */ +#define LCD_CTRL_BPP_16 4 /* 15/16 bpp */ +#define LCD_CTRL_BPP_18_24 5 /* 18/24/32 bpp */ +#define LCD_CTRL_BPP_MASK 0x07 + +/* Palette buffer (LCD_CMDx.PAL). */ + +#define LCD_CMD_PAL (1 << 28) + +#endif /* __JZLCD_H__ */ diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/memory.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/memory.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,78 @@ +/* + * Memory allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include + +#include "memory.h" + +int get_device(char const *hid, l4io_device_handle_t *dh, l4io_resource_handle_t *rh) +{ + return l4io_lookup_device(hid, dh, 0, rh); +} + +int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type) +{ + int current = 0, result = 0; + l4_cap_idx_t vbus = l4re_env_get_cap("vbus"); + + do + { + result = l4vbus_get_resource(vbus, dh, current, res); + current++; + } + while ((!result) && (res->type != type)); + + return result; +} + +int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end) +{ + l4io_device_handle_t dh; + l4io_resource_handle_t rh; + l4io_resource_t res; + int result; + + result = get_device(hid, &dh, &rh); + + if (result < 0) + return result; + + result = get_resource(dh, &res, L4IO_RESOURCE_MEM); + + if (result) + return result; + + result = l4io_request_iomem(res.start, res.end - res.start + 1, + L4IO_MEM_NONCACHED, start); + + if (result) + return result; + + *end = *start + (res.end - res.start + 1); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/memory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/memory.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,36 @@ +/* + * Memory allocation utility functions. + * + * Copyright (C) 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#ifndef __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ +#define __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ + +#include +#include + +int get_device(char const *hid, l4io_device_handle_t *dh, + l4io_resource_handle_t *rh); + +int get_resource(l4io_device_handle_t dh, l4io_resource_t *res, + enum l4io_resource_types_t type); + +int get_memory(char const *hid, l4_addr_t *start, l4_addr_t *end); + +#endif /* __DRIVERS_LCD_ARCH_JZ4740_MEMORY_H__ */ diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/nanonote_gpm940b0.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/nanonote_gpm940b0.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,37 @@ +/* + * Ben NanoNote screen details. + * + * Copyright (C) Xiangfu Liu + * Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "jzlcd.h" + +struct jzfb_info nanonote_fb_info = { + .cfg=MODE_8BIT_SERIAL_TFT | PCLK_N | HSYNC_N | VSYNC_N | DE_P, + .w=320, .h=240, /* dimensions */ + .bpp=32, /* bits per pixel */ + .fclk=70, /* frame clock rate */ + .hsw=1, .vsw=1, /* sync widths */ + .elw=273, .blw=140, /* line limits: end/front, beginning/back porch */ + .efw=1, .bfw=20, /* frame limits: end/front, beginning/back porch */ +}; + +vidinfo_t nanonote_panel_info = { + .jz_fb=&nanonote_fb_info /* wrap the above */ +}; diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/nanonote_gpm940b0.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/nanonote_gpm940b0.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,8 @@ +#ifndef __NANONOTE_GPM940B0_H__ +#define __NANONOTE_GPM940B0_H__ + +#include "jzlcd.h" + +extern vidinfo_t nanonote_panel_info; + +#endif /* __NANONOTE_GPM940B0_H__ */ diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/qi_lb60_lcd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/qi_lb60_lcd.c Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,297 @@ +/* + * Access the LCD and related GPIOs on the Ben NanoNote. + * + * (c) 2017, 2018 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "nanonote_gpm940b0.h" +#include "jzlcd.h" +#include "xburst_types.h" +#include "memory.h" + +enum Jz4740_lcd_gpio +{ + Jz4740_lcd_gpio_spen = 21, /* serial command enable */ + Jz4740_lcd_gpio_spda = 22, /* serial command clock */ + Jz4740_lcd_gpio_spck = 23, /* serial command data */ +}; + +/* Peripheral memory regions. */ + +static l4_addr_t cpm_virt_base = 0, cpm_virt_base_end = 0; +static l4_addr_t gpio_virt_base = 0, gpio_virt_base_end = 0; +static l4_addr_t lcd_virt_base = 0, lcd_virt_base_end = 0; + +/* Device abstractions. */ + +static void *gpio_port_c; +static void *cpm_device = 0; +static vidinfo_t *panel_info = 0; + +/* Framebuffer and descriptor regions. */ + +static void *fb_vaddr = 0, *desc_vaddr = 0; +static l4_addr_t fb_paddr = 0, desc_paddr = 0; +static l4_size_t fb_size, desc_size; + + + +// Write SPI values via the LCD GPIO pins. + +static void spi_write_reg(uint8_t reg, uint8_t val) +{ + uint8_t no; + uint16_t value; + + jz4740_gpio_set(gpio_port_c, Jz4740_lcd_gpio_spen, 1); + jz4740_gpio_set(gpio_port_c, Jz4740_lcd_gpio_spck, 1); + jz4740_gpio_set(gpio_port_c, Jz4740_lcd_gpio_spda, 0); + jz4740_gpio_set(gpio_port_c, Jz4740_lcd_gpio_spen, 0); + + value = ((reg << 8) | (val & 0xFF)); + + /* Clock data using the clock and data outputs. */ + + for (no = 0; no < 16; no++) + { + jz4740_gpio_set(gpio_port_c, Jz4740_lcd_gpio_spck, 0); + jz4740_gpio_set(gpio_port_c, Jz4740_lcd_gpio_spda, value & 0x8000 ? 1 : 0); + jz4740_gpio_set(gpio_port_c, Jz4740_lcd_gpio_spck, 1); + value = (value << 1); + } + + jz4740_gpio_set(gpio_port_c, Jz4740_lcd_gpio_spen, 1); +} + +// GPIO-based operations. + +static void lcd_display_pin_init(void) +{ + Pin_slice mask = {.offset=0, .mask=(1 << Jz4740_lcd_gpio_spen) | (1 << Jz4740_lcd_gpio_spck) | (1 << Jz4740_lcd_gpio_spda)}; + Pin_slice slcd8_mask = {.offset=0, .mask=0x003c00ff}; + + /* Configure SPI pins. */ + + jz4740_gpio_multi_setup(gpio_port_c, &mask, L4VBUS_GPIO_SETUP_OUTPUT, 0); + + /* Configure SLCD8 pins. */ + + jz4740_gpio_multi_config_pad(gpio_port_c, &slcd8_mask, Function_alt, 0); +} + +static void lcd_display_on(void) +{ + spi_write_reg(0x05, 0x1e); // GRB=0 (reset); PWM_DUTY=0b011 (70%, default); SHDB2=1, SHDB1=1 (power-related); STB=0 (standby) + spi_write_reg(0x05, 0x5e); // GRB=1 (normal operation); ... + spi_write_reg(0x07, 0x8d); // HBLK=141 (horizontal blanking period from start of hsync pulse to data start) + spi_write_reg(0x13, 0x01); // IN_SEL=1 (alignment mode) + spi_write_reg(0x05, 0x5f); // ...; STB=1 (not standby) +} + +/* CPM operations. */ + +static void lcd_set_timing(vidinfo_t *vid) +{ + uint32_t pclk = jz4740_lcd_get_pixel_clock(vid); + + jz4740_cpm_stop_lcd(cpm_device); + + /* + Original comment: LCDClock > 2.5*Pixclock + However, the documentation indicates that a TFT panel needs a device clock + 1.5 times that of the pixel clock, and a STN panel needs a device clock 3 + times that of the pixel clock. + */ + + jz4740_cpm_set_lcd_frequencies(cpm_device, pclk, 3); + jz4740_cpm_update_output_frequency(cpm_device); + jz4740_cpm_start_lcd(cpm_device); + + l4_sleep(1); // 1ms == 1000us +} + + + +static int setup_memory(void) +{ + l4re_ds_t fbmem, descmem; + l4_size_t fb_size_out, desc_size_out; + int result = 0; + + if (fb_vaddr) + return 0; + + if (!panel_info) + return 1; + + fb_size = jz4740_lcd_get_screen_size(panel_info); + desc_size = jz4740_lcd_get_descriptors_size(panel_info); + + /* Obtain resource details describing the I/O memory. */ + + if ((result = get_memory("jz4740-cpm", &cpm_virt_base, &cpm_virt_base_end)) < 0) + return 1; + + if ((result = get_memory("jz4740-lcd", &lcd_virt_base, &lcd_virt_base_end)) < 0) + return 1; + + if ((result = get_memory("jz4740-gpio", &gpio_virt_base, &gpio_virt_base_end)) < 0) + return 1; + + /* Set the framebuffer up. */ + + fbmem = l4re_util_cap_alloc(); + descmem = l4re_util_cap_alloc(); + + if (l4_is_invalid_cap(fbmem) || l4_is_invalid_cap(descmem)) + return 1; + + /* Allocate memory for the framebuffer at 2**6 == 64 byte == 16 word alignment, + also for the descriptors. */ + + if (l4re_ma_alloc_align(fb_size, fbmem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 6) || + l4re_ma_alloc_align(desc_size, descmem, L4RE_MA_CONTINUOUS | L4RE_MA_PINNED, 6)) + return 1; + + /* Map the allocated memory, obtaining virtual addresses. */ + + if (l4re_rm_attach(&fb_vaddr, fb_size, + L4RE_RM_SEARCH_ADDR | L4RE_RM_EAGER_MAP, + fbmem, 0, L4_PAGESHIFT) || + l4re_rm_attach(&desc_vaddr, desc_size, + L4RE_RM_SEARCH_ADDR | L4RE_RM_EAGER_MAP, + descmem, 0, L4_PAGESHIFT)) + return 1; + + fb_size_out = fb_size; + desc_size_out = desc_size; + + if (l4re_ds_phys(fbmem, 0, &fb_paddr, &fb_size_out) || + l4re_ds_phys(descmem, 0, &desc_paddr, &desc_size_out)) + return 1; + + if ((fb_size_out != fb_size) || (desc_size_out != desc_size)) + return 1; + + cpm_device = jz4740_cpm_init(cpm_virt_base); + gpio_port_c = jz4740_gpio_init(gpio_virt_base + 0x200, gpio_virt_base + 0x300, 32); + + return 0; +} + +static void enable(void) +{ + if (setup_memory()) + return; + + jz4740_lcd_set_base(panel_info, (void *) lcd_virt_base); + jz4740_lcd_disable(panel_info); + + // Initialise the LCD controller and structures. + + jz4740_lcd_ctrl_init( + (struct jz_fb_dma_descriptor *) desc_vaddr, + (struct jz_fb_dma_descriptor *) desc_paddr, + fb_vaddr, + (void *) fb_paddr, + panel_info); + + // Initialise the LCD peripheral. + + jz4740_lcd_hw_init(panel_info); + + // Initialise the clocks for the LCD controller. + + lcd_set_timing(panel_info); + + // Switch the display on using GPIO operations. + + lcd_display_pin_init(); + lcd_display_on(); + + // Finally, enable the peripheral. + + jz4740_lcd_enable(panel_info); +} + + + +int main(void) +{ + l4_size_t *fb; + l4_size_t i, mask, value, onpix, offpix; + + /* Configure the LCD. */ + + panel_info = &nanonote_panel_info; + enable(); + + fb = (l4_size_t *) fb_vaddr; + + /* Try and show some values. */ + + onpix = 0xffaaffaa; offpix = 0x11551155; + mask = 0x80000000; value = 0x80000001; + + i = 0; + + while (i < fb_size / 4) + { + fb[i] = value & mask ? onpix : offpix; + i++; + + if ((i % 10) == 0) + { + if (mask == 1) mask = 0x80000000; + else mask >>= 1; + + onpix = (onpix >> 8) | ((onpix & 0xff) << 24); + offpix = (offpix >> 8) | ((offpix & 0xff) << 24); + + if (i == 3200) value = jz4740_cpm_get_lcd_pixel_divider(cpm_device); + else if (i == 6400) value = jz4740_cpm_get_lcd_pixel_frequency(cpm_device); + else if (i == 9600) value = (l4_size_t) fb_vaddr; + else if (i == 12800) value = fb_paddr; + else if (i == 16000) value = ((struct jz_fb_dma_descriptor *) desc_vaddr)[0].fsadr; + else if (i == 19200) value = REG32(lcd_virt_base + 0x00); + else if (i == 22400) value = REG32(lcd_virt_base + 0x04); + else if (i == 25600) value = REG32(lcd_virt_base + 0x30); + else if (i == 28800) value = REG32(lcd_virt_base + 0x40); + } + } + + l4_cache_clean_data((long unsigned int) fb_vaddr, (long unsigned int) fb_vaddr + fb_size); + + while (1); + + return 0; +} diff -r 000000000000 -r 89a1bc19c1fc pkg/landfall-examples/qi_lb60_lcd/xburst_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/landfall-examples/qi_lb60_lcd/xburst_types.h Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,31 @@ +/* + * Ingenic XBurst type definitions. + * + * Copyright 2009 (C) Qi Hardware Inc. + * Author: Xiangfu Liu + * Copyright (C) 2017 Paul Boddie + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __XBURST_TYPES_H__ +#define __XBURST_TYPES_H__ + +#include + +#define REG8(addr) *((volatile uint8_t *)(addr)) +#define REG16(addr) *((volatile uint16_t *)(addr)) +#define REG32(addr) *((volatile uint32_t *)(addr)) + +#endif /* __XBURST_TYPES_H__ */ diff -r 000000000000 -r 89a1bc19c1fc tools/install.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/install.sh Sun May 13 01:34:16 2018 +0200 @@ -0,0 +1,73 @@ +#!/bin/sh + +THISDIR=`dirname "$0"` +DIRNAME=`realpath "$THISDIR/.."` +PROGNAME=`basename "$0"` + +if [ "$1" = '--help' ]; then + cat 1>&2 < [ --clean ] + +Copy the distributed packages into the "pkg" hierarchy found within the +specified directory. Also copy the distributed configuration examples into the +"conf" hierarchy. + +The indicated directory need not be called "l4", but it must at least have a +"conf" directory and a "pkg" directory inside it. + +Specifying --clean removes copied objects. +EOF + exit 1 +fi + +# Test for a directory argument and whether it exists. + +if [ ! "$1" ] || [ ! -e "$1" ] ; then + cat 1>&2 <&2 <