summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2016-08-03 12:55:46 +0200
committerNicolas Schodet2019-10-09 23:05:50 +0200
commitc5162d97ad6059cfea292beaf3b9a7b67ca8f982 (patch)
tree1eaed8ba3ef75cbccc74a4bdcd9a1f63e38486dd
parent12b16664f756046e29b3e4114b5b8725f74fdd81 (diff)
ucoo/hal/frame_buffer: add LTDC, DSI & DMA2D
-rw-r--r--ucoo/arch/reg.stm32f4.hh5
-rw-r--r--ucoo/hal/frame_buffer/Module6
-rw-r--r--ucoo/hal/frame_buffer/dma2d.stm32f4.cc187
-rw-r--r--ucoo/hal/frame_buffer/dma2d.stm32f4.hh49
-rw-r--r--ucoo/hal/frame_buffer/dsi.stm32f4.cc218
-rw-r--r--ucoo/hal/frame_buffer/dsi.stm32f4.hh56
-rw-r--r--ucoo/hal/frame_buffer/ltdc.stm32f4.cc86
-rw-r--r--ucoo/hal/frame_buffer/ltdc.stm32f4.hh53
8 files changed, 659 insertions, 1 deletions
diff --git a/ucoo/arch/reg.stm32f4.hh b/ucoo/arch/reg.stm32f4.hh
index 1f5f2cf..6cedaba 100644
--- a/ucoo/arch/reg.stm32f4.hh
+++ b/ucoo/arch/reg.stm32f4.hh
@@ -128,6 +128,11 @@
#define DESIG_FLASH_SIZE_BASE 0x1fff7a22
#define DESIG_UNIQUE_ID_BASE 0x1fff7a10
+#define DMA2D_CR_MODE_MemoryToMemory 0
+#define DMA2D_CR_MODE_MemoryToMemoryFPC DMA2D_CR_MODE_0
+#define DMA2D_CR_MODE_MemoryToMemoryBlend DMA2D_CR_MODE_1
+#define DMA2D_CR_MODE_RegisterToMemory (DMA2D_CR_MODE_1 | DMA2D_CR_MODE_0)
+
#ifdef DSI_BASE
# define DSI_VMCR_VMT_NonBurstSyncPulses 0
# define DSI_VMCR_VMT_NonBurstSyncEvents 1
diff --git a/ucoo/hal/frame_buffer/Module b/ucoo/hal/frame_buffer/Module
index 699de5b..b4c2e40 100644
--- a/ucoo/hal/frame_buffer/Module
+++ b/ucoo/hal/frame_buffer/Module
@@ -1,4 +1,8 @@
-ucoo_hal_frame_buffer_SOURCES := sdl_frame_buffer.host.cc
+ucoo_hal_frame_buffer_SOURCES := \
+ dma2d.stm32f4.cc \
+ dsi.stm32f4.cc \
+ ltdc.stm32f4.cc \
+ sdl_frame_buffer.host.cc
SDL_CFLAGS = $(shell sdl2-config --cflags)
SDL_LIBS = $(shell sdl2-config --libs)
diff --git a/ucoo/hal/frame_buffer/dma2d.stm32f4.cc b/ucoo/hal/frame_buffer/dma2d.stm32f4.cc
new file mode 100644
index 0000000..3ec0dad
--- /dev/null
+++ b/ucoo/hal/frame_buffer/dma2d.stm32f4.cc
@@ -0,0 +1,187 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/frame_buffer/dma2d.stm32f4.hh"
+#include "ucoo/arch/reg.hh"
+
+namespace ucoo {
+
+void
+dma2d_wait ()
+{
+ while (reg::DMA2D->CR & DMA2D_CR_START)
+ ;
+}
+
+void
+dma2d_fill (Surface &dst, const Surface::Rect &rect, uint32_t color)
+{
+ // Handle clipping.
+ int x = rect.x, y = rect.y, w = rect.w, h = rect.h;
+ if (x < 0)
+ {
+ w += x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ h += y;
+ y = 0;
+ }
+ if (x + w > dst.w)
+ w = dst.w - x;
+ if (y + h > dst.h)
+ h = dst.h - y;
+ if (w < 0 || h < 0)
+ return;
+ // Wait for DMA2D to be idle.
+ dma2d_wait ();
+ // Fill.
+ switch (dst.format)
+ {
+ case Surface::Format::ARGB8888:
+ case Surface::Format::RGB888:
+ reg::DMA2D->OCOLR = color;
+ break;
+ case Surface::Format::RGB565:
+ {
+ uint32_t r = (color >> 19) & 0x1f;
+ uint32_t g = (color >> 10) & 0x3f;
+ uint32_t b = (color >> 3) & 0x1f;
+ reg::DMA2D->OCOLR = r << 11 | g << 5 | b;
+ }
+ break;
+ case Surface::Format::ARGB4444:
+ {
+ uint32_t r = (color >> 20) & 0xf;
+ uint32_t g = (color >> 12) & 0xf;
+ uint32_t b = (color >> 4) & 0xf;
+ reg::DMA2D->OCOLR = r << 8 | g << 4 | b;
+ }
+ break;
+ case Surface::Format::A8:
+ case Surface::Format::A4:
+ assert_unreachable ();
+ }
+ int bpp = dst.bpp ();
+ reg::DMA2D->OPFCCR = static_cast<int> (dst.format) & 0xff;
+ reg::DMA2D->OMAR = reinterpret_cast<intptr_t> (dst.pixels)
+ + (y * dst.stride + x) * bpp / 8;
+ reg::DMA2D->OOR = dst.stride - w;
+ reg::DMA2D->NLR = w << 16 | h;
+ reg::DMA2D->CR = DMA2D_CR_MODE_RegisterToMemory | DMA2D_CR_START;
+}
+
+void
+dma2d_blit (const Surface &dst, const Surface &src, int x, int y)
+{
+ int sx = 0, sy = 0, sw = src.w, sh = src.h;
+ // Handle clipping.
+ if (x < 0)
+ {
+ sw += x;
+ sx = -x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ sh += y;
+ sy = -y;
+ y = 0;
+ }
+ if (x + sw > dst.w)
+ sw = dst.w - x;
+ if (y + sh > dst.h)
+ sh = dst.h - y;
+ if (sw < 0 || sh < 0)
+ return;
+ // Wait for DMA2D to be idle.
+ dma2d_wait ();
+ // Blit.
+ int srcbpp = src.bpp ();
+ int dstbpp = dst.bpp ();
+ reg::DMA2D->FGMAR = reinterpret_cast<intptr_t> (src.pixels)
+ + (sy * src.stride + sx) * srcbpp / 8;
+ reg::DMA2D->FGOR = src.stride - sw;
+ reg::DMA2D->FGPFCCR = static_cast<int> (src.format) & 0xff;
+ reg::DMA2D->OPFCCR = static_cast<int> (dst.format) & 0xff;
+ reg::DMA2D->OMAR = reinterpret_cast<intptr_t> (dst.pixels)
+ + (y * dst.stride + x) * dstbpp / 8;
+ reg::DMA2D->OOR = dst.stride - sw;
+ reg::DMA2D->NLR = sw << 16 | sh;
+ if (src.format == dst.format)
+ reg::DMA2D->CR = DMA2D_CR_MODE_MemoryToMemory | DMA2D_CR_START;
+ else
+ reg::DMA2D->CR = DMA2D_CR_MODE_MemoryToMemoryFPC | DMA2D_CR_START;
+}
+
+void
+dma2d_blend (const Surface &dst, const Surface &src, int x, int y,
+ uint32_t const_color)
+{
+ int sx = 0, sy = 0, sw = src.w, sh = src.h;
+ // Handle clipping.
+ if (x < 0)
+ {
+ sw += x;
+ sx = -x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ sh += y;
+ sy = -y;
+ y = 0;
+ }
+ if (x + sw > dst.w)
+ sw = dst.w - x;
+ if (y + sh > dst.h)
+ sh = dst.h - y;
+ if (sw < 0 || sh < 0)
+ return;
+ // Wait for DMA2D to be idle.
+ dma2d_wait ();
+ // Blend.
+ int srcbpp = src.bpp ();
+ int dstbpp = dst.bpp ();
+ reg::DMA2D->FGMAR = reinterpret_cast<intptr_t> (src.pixels)
+ + (sy * src.stride + sx) * srcbpp / 8;
+ reg::DMA2D->FGOR = src.stride - sw;
+ uint32_t bgmar = reinterpret_cast<intptr_t> (dst.pixels)
+ + (y * dst.stride + x) * dstbpp / 8;
+ reg::DMA2D->BGMAR = bgmar;
+ uint32_t bgor = dst.stride - sw;
+ reg::DMA2D->BGOR = bgor;
+ reg::DMA2D->FGPFCCR = (const_color & 0xff000000)
+ | DMA2D_FGPFCCR_AM_1
+ | (static_cast<int> (src.format) & 0xff);
+ reg::DMA2D->FGCOLR = const_color & 0xffffff;
+ reg::DMA2D->BGPFCCR = static_cast<int> (dst.format) & 0xff;
+ reg::DMA2D->OPFCCR = static_cast<int> (dst.format) & 0xff;
+ reg::DMA2D->OMAR = bgmar;
+ reg::DMA2D->OOR = bgor;
+ reg::DMA2D->NLR = sw << 16 | sh;
+ reg::DMA2D->CR = DMA2D_CR_MODE_MemoryToMemoryBlend | DMA2D_CR_START;
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/frame_buffer/dma2d.stm32f4.hh b/ucoo/hal/frame_buffer/dma2d.stm32f4.hh
new file mode 100644
index 0000000..f70ead2
--- /dev/null
+++ b/ucoo/hal/frame_buffer/dma2d.stm32f4.hh
@@ -0,0 +1,49 @@
+#ifndef ucoo_hal_frame_buffer_dma2d_stm32_hh
+#define ucoo_hal_frame_buffer_dma2d_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/frame_buffer.hh"
+
+namespace ucoo {
+
+/// Wait until all operations are done.
+void
+dma2d_wait ();
+
+/// Fill given rect in surface, with clipping.
+void
+dma2d_fill (Surface &dst, const Surface::Rect &rect, uint32_t color);
+
+/// Blit surface in another surface, with clipping.
+void
+dma2d_blit (const Surface &dst, const Surface &src, int x, int y);
+
+/// Blend surface in another surface, with clipping.
+void
+dma2d_blend (const Surface &dst, const Surface &src, int x, int y,
+ uint32_t const_color = 0xff000000);
+
+} // namespace ucoo
+
+#endif // ucoo_hal_frame_buffer_dma2d_stm32_hh
diff --git a/ucoo/hal/frame_buffer/dsi.stm32f4.cc b/ucoo/hal/frame_buffer/dsi.stm32f4.cc
new file mode 100644
index 0000000..31a71f4
--- /dev/null
+++ b/ucoo/hal/frame_buffer/dsi.stm32f4.cc
@@ -0,0 +1,218 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/frame_buffer/dsi.stm32f4.hh"
+
+#include "ucoo/arch/reg.hh"
+#include "ucoo/arch/rcc.stm32.hh"
+
+namespace ucoo {
+
+enum DsiDataType
+{
+ SYNC_EVENT_VSYNC_START = 0x01,
+ SYNC_EVENT_VSYNC_END = 0x11,
+ SYNC_EVENT_HSYNC_START = 0x21,
+ SYNC_EVENT_HSYNC_END = 0x31,
+ END_OF_TRANSMISSION = 0x08,
+ COLOR_MODE_OFF = 0x02,
+ COLOR_MODE_ON = 0x12,
+ NULL_PACKET = 0x09,
+ BLANKING_PACKET = 0x19,
+ GENERIC_SHORT_WRITE_PARAM_0 = 0x03,
+ GENERIC_SHORT_WRITE_PARAM_1 = 0x13,
+ GENERIC_SHORT_WRITE_PARAM_2 = 0x23,
+ GENERIC_READ_PARAM_0 = 0x04,
+ GENERIC_READ_PARAM_1 = 0x14,
+ GENERIC_READ_PARAM_2 = 0x24,
+ DCS_SHORT_WRITE_PARAM_0 = 0x05,
+ DCS_SHORT_WRITE_PARAM_1 = 0x15,
+ DCS_READ = 0x06,
+ SET_MAX_RETURN_SIZE = 0x37,
+ GENERIC_LONG_WRITE = 0x29,
+ DCS_LONG_WRITE = 0x39,
+ PACKED_PIXEL_RGB565 = 0x0e,
+ PACKED_PIXEL_RGB666 = 0x1e,
+ PACKED_PIXEL_RGB666_LOOSE = 0x2e,
+ PACKED_PIXEL_RGB888 = 0x3e,
+};
+
+Dsi::Dsi (int width, int heigth, int lanes)
+ : Ltdc (width, heigth, 2, 1, 1, 2, 1, 1), lanes_ (lanes)
+{
+}
+
+void
+Dsi::enable (const Function<void ()> &config)
+{
+ // TODO: make this more configurable.
+ // Enable clocks.
+ rcc_peripheral_clock_enable (Rcc::DSI);
+ // Enable DSI regulator.
+ reg::DSI->WRPCR = DSI_WRPCR_REGEN;
+ while (!(reg::DSI->WISR & DSI_WISR_RRS))
+ ;
+ // Enable PLL, 500 MHz output frequency (HSE @ 8 MHz).
+ const int phy_hz = 500000000;
+ reg::DSI->WRPCR = DSI_WRPCR_REGEN
+ | (125 << DSI_WRPCR_PLL_NDIV_Pos)
+ | (2 << DSI_WRPCR_PLL_IDF_Pos)
+ | DSI_WRPCR_PLL_ODF_Div1;
+ reg::DSI->WRPCR |= DSI_WRPCR_PLLEN;
+ while (!(reg::DSI->WISR & DSI_WISR_PLLLS))
+ ;
+ //// D-PHY parameters.
+ // Setup Unit interval.
+ reg::DSI->WPCR[0] = 4000000000u / phy_hz;
+ // Number of lanes.
+ reg::DSI->PCONFR = lanes_ - 1;
+ // Clock control.
+ reg::DSI->CLCR = DSI_CLCR_DPCC;
+ // TODO: Time for LP/HS and HS/LP transition in CLTCR/DLTCR.
+ // TODO: Stop wait time in PCONFR.
+ //// Timings.
+ // TX escape clock division factor.
+ reg::DSI->CCR = 4; // 500 MHz / 8 (bit) / 4 < 20 MHz
+ // TX timeouts.
+ reg::DSI->CCR |= 4 << 8;
+ reg::DSI->TCCR[0] = 0x01000000;
+ reg::DSI->TCCR[1] = 0x00000100;
+ reg::DSI->TCCR[2] = 0x00000100;
+ reg::DSI->TCCR[3] = 0x00000100;
+ reg::DSI->TCCR[4] = 0x00000100;
+ reg::DSI->TCCR[5] = 0x00000100;
+ //// Flow control & DBI interface.
+ reg::DSI->CMCR = DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX
+ | DSI_CMCR_GSR0TX | DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX | DSI_CMCR_GLWTX
+ | DSI_CMCR_DSW0TX | DSI_CMCR_DSW1TX | DSI_CMCR_DSR0TX | DSI_CMCR_DLWTX
+ | DSI_CMCR_MRDPS;
+ reg::DSI->GVCIDR = 0;
+ //// LTDC interface.
+ // Virtual channel for LTDC traffic.
+ reg::DSI->LVCIDR = 0;
+ // Color coding for the host and wrapper.
+ reg::DSI->LCOLCR = DSI_LCOLCR_COLC_24Bit;
+ reg::DSI->WCFGR = (reg::DSI->WCFGR & ~DSI_WCFGR_COLMUX)
+ | DSI_WCFGR_COLMUX_24Bit;
+ // Polarity of control signals.
+ reg::DSI->LPCR = 0; // HSP, VSP, DEP
+ reg::DSI->WCFGR |= 0; // VSPOL
+ //// Configure adapted command mode.
+ // Command mode.
+ reg::DSI->MCR |= DSI_MCR_CMDM;
+ reg::DSI->WCFGR |= DSI_WCFGR_DSIM;
+ // Maximum memory write.
+ reg::DSI->LCCR = width_;
+ // Tearing effect source and polarity, no automatic refresh.
+ reg::DSI->WCFGR &= ~(DSI_WCFGR_TESRC | DSI_WCFGR_AR);
+ // Tearing effect acknowledge.
+ reg::DSI->CMCR |= DSI_CMCR_TEARE;
+ //// Enable D-PHY and D-PHY clock lane settings.
+ reg::DSI->PCTLR = DSI_PCTLR_DEN;
+ reg::DSI->PCTLR = DSI_PCTLR_CKE | DSI_PCTLR_DEN;
+ //// Configure LTDC.
+ rcc_sai_pll_setup (8000000,
+ 4, // pllm => 8 MHz / 4 = 2 MHz
+ 208, // plln => 2 MHz * 208 = 416 MHz
+ 8, // pllp => 416 MHz / 8 = 52 MHz
+ 15, 32, // pllq, pllq_div => 416 MHz / 15 / 32 ~= 0.86 MHz
+ 5, 2); // pllr, pllr_div => 416 MHz / 5 / 2 ~= 41.6 MHz
+ Ltdc::enable ();
+ //// Enable DSI Host and DSI wrapper.
+ reg::DSI->CR = DSI_CR_EN;
+ reg::DSI->WCR = DSI_WCR_DSIEN;
+ //// Configure display.
+ config ();
+ //// Flow control & DBI interface.
+ reg::DSI->CMCR &= ~(DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX
+ | DSI_CMCR_GSR0TX | DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX
+ | DSI_CMCR_GLWTX | DSI_CMCR_DSW0TX | DSI_CMCR_DSW1TX
+ | DSI_CMCR_DSR0TX | DSI_CMCR_DLWTX | DSI_CMCR_MRDPS);
+ reg::DSI->PCR = DSI_PCR_BTAE;
+}
+
+void
+Dsi::disable ()
+{
+ // TODO
+ reg::DSI->CR = 0;
+ reg::DSI->WCR = 0;
+ Ltdc::disable ();
+ rcc_peripheral_clock_disable (Rcc::DSI);
+}
+
+void
+Dsi::layer_setup (int layer, const Surface &surface, int x, int y)
+{
+ reg::DSI->WCR &= ~DSI_WCR_DSIEN;
+ Ltdc::layer_setup (layer, surface, x, y);
+ reg::DSI->WCR |= DSI_WCR_DSIEN;
+}
+
+void
+Dsi::refresh ()
+{
+ ucoo::reg::DSI->WCR |= DSI_WCR_LTDCEN;
+}
+
+void
+Dsi::write_command (std::initializer_list<uint8_t> data)
+{
+ while (!(reg::DSI->GPSR & DSI_GPSR_CMDFE))
+ ;
+ uint32_t w = 0;
+ int wb = 0;
+ for (auto d : data)
+ {
+ w |= d << wb;
+ wb += 8;
+ if (wb == 32)
+ {
+ reg::DSI->GPDR = w;
+ w = 0;
+ wb = 0;
+ }
+ }
+ if (data.size () == 1)
+ {
+ reg::DSI->GHCR = DCS_SHORT_WRITE_PARAM_0 * DSI_GHCR_DT0
+ | 0 * DSI_GHCR_VCID0
+ | w * DSI_GHCR_WCLSB0;
+ }
+ else if (data.size () == 2)
+ {
+ reg::DSI->GHCR = DCS_SHORT_WRITE_PARAM_1 * DSI_GHCR_DT0
+ | 0 * DSI_GHCR_VCID0
+ | w * DSI_GHCR_WCLSB0;
+ }
+ else
+ {
+ if (wb)
+ reg::DSI->GPDR = w;
+ reg::DSI->GHCR = DCS_LONG_WRITE * DSI_GHCR_DT0
+ | 0 * DSI_GHCR_VCID0
+ | data.size () * DSI_GHCR_WCLSB0;
+ }
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/frame_buffer/dsi.stm32f4.hh b/ucoo/hal/frame_buffer/dsi.stm32f4.hh
new file mode 100644
index 0000000..bb92d6d
--- /dev/null
+++ b/ucoo/hal/frame_buffer/dsi.stm32f4.hh
@@ -0,0 +1,56 @@
+#ifndef ucoo_hal_frame_buffer_dsi_stm32f4_hh
+#define ucoo_hal_frame_buffer_dsi_stm32f4_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/frame_buffer/ltdc.stm32f4.hh"
+#include "ucoo/utils/function.hh"
+
+#include <initializer_list>
+
+namespace ucoo {
+
+/// DSI controller, in Adapted Command mode.
+class Dsi : public Ltdc
+{
+ public:
+ /// Constructor.
+ Dsi (int width, int heigth, int lanes);
+ /// Enable controller.
+ void enable (const Function<void ()> &config);
+ /// Disable controller.
+ void disable ();
+ /// Setup a layer.
+ void layer_setup (int layer, const Surface &surface, int x, int y);
+ /// Refresh screen.
+ static void refresh ();
+ /// Write a command to display.
+ static void write_command (std::initializer_list<uint8_t> data);
+ private:
+ /// Number of data lanes.
+ int lanes_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_frame_buffer_dsi_stm32f4_hh
diff --git a/ucoo/hal/frame_buffer/ltdc.stm32f4.cc b/ucoo/hal/frame_buffer/ltdc.stm32f4.cc
new file mode 100644
index 0000000..4255ff7
--- /dev/null
+++ b/ucoo/hal/frame_buffer/ltdc.stm32f4.cc
@@ -0,0 +1,86 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/frame_buffer/ltdc.stm32f4.hh"
+
+#include "ucoo/arch/reg.hh"
+#include "ucoo/arch/rcc.stm32.hh"
+
+namespace ucoo {
+
+Ltdc::Ltdc (int width, int heigth,
+ int hsync, int hbp, int hfp,
+ int vsync, int vbp, int vfp)
+ : width_ (width), heigth_ (heigth),
+ hsync_ (hsync), hbp_ (hbp), hfp_ (hfp),
+ vsync_ (vsync), vbp_ (vbp), vfp_ (vfp)
+{
+}
+
+void
+Ltdc::enable ()
+{
+ // TODO: make this more configurable.
+ // Enable clocks.
+ rcc_peripheral_clock_enable (Rcc::LTDC);
+ // Polarity of control signals.
+ reg::LTDC->GCR &= (LTDC_GCR_HSPOL | LTDC_GCR_VSPOL | LTDC_GCR_DEPOL
+ | LTDC_GCR_PCPOL);
+ // Timings.
+ reg::LTDC->SSCR = (hsync_ - 1) << 16 | (vsync_ - 1);
+ reg::LTDC->BPCR = (hsync_ + hbp_ - 1) << 16 | (vsync_ + vbp_ - 1);
+ reg::LTDC->AWCR = (hsync_ + hbp_ + width_ - 1) << 16
+ | (vsync_ + vbp_ + heigth_ - 1);
+ reg::LTDC->TWCR = (hsync_ + hbp_ + width_ + hfp_ - 1) << 16
+ | (vsync_ + vbp_ + heigth_ + vfp_ - 1);
+ // Enable.
+ reg::LTDC->GCR |= LTDC_GCR_LTDCEN;
+}
+
+void
+Ltdc::disable ()
+{
+ reg::LTDC->GCR &= ~LTDC_GCR_LTDCEN;
+ rcc_peripheral_clock_disable (Rcc::LTDC);
+ // TODO: shut down PLL.
+}
+
+void
+Ltdc::layer_setup (int layer, const Surface &surface, int x, int y)
+{
+ auto reg = layer == 0 ? reg::LTDC_Layer1 : reg::LTDC_Layer2;
+ reg->WHPCR = (hsync_ + hbp_ + x + surface.w - 1) << 16
+ | (hsync_ + hbp_ + x);
+ reg->WVPCR = (vsync_ + vbp_ + y + surface.h - 1) << 16
+ | (vsync_ + vbp_ + y);
+ reg->PFCR = static_cast<int> (surface.format) & 0xff;
+ reg->CFBAR = reinterpret_cast<uintptr_t> (surface.pixels);
+ reg->CFBLR = (surface.stride * surface.bpp () / 8) << 16
+ | (surface.w * surface.bpp () / 8 + 3);
+ reg->CFBLNR = surface.h;
+ reg->CR = LTDC_LxCR_LEN;
+ // Load parameters.
+ reg::LTDC->SRCR = LTDC_SRCR_IMR;
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/frame_buffer/ltdc.stm32f4.hh b/ucoo/hal/frame_buffer/ltdc.stm32f4.hh
new file mode 100644
index 0000000..edf95b0
--- /dev/null
+++ b/ucoo/hal/frame_buffer/ltdc.stm32f4.hh
@@ -0,0 +1,53 @@
+#ifndef ucoo_hal_frame_buffer_ltdc_stm32f4_hh
+#define ucoo_hal_frame_buffer_ltdc_stm32f4_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2016 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/frame_buffer.hh"
+
+namespace ucoo {
+
+/// LTDC controller.
+class Ltdc
+{
+ public:
+ /// Constructor, take timing parameters.
+ Ltdc (int width, int heigth,
+ int hsync, int hbp, int hfp,
+ int vsync, int vbp, int vfp);
+ /// Enable controller.
+ void enable ();
+ /// Disable controller.
+ void disable ();
+ /// Setup a layer.
+ void layer_setup (int layer, const Surface &surface, int x, int y);
+ protected:
+ int width_, heigth_;
+ private:
+ int hsync_, hbp_, hfp_;
+ int vsync_, vbp_, vfp_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_frame_buffer_ltdc_stm32f4_hh