Move OMAP4 support to world

Fix #202
This commit is contained in:
Stefan Kalkowski
2020-03-23 14:49:22 +01:00
committed by Norman Feske
parent 0ed545e55a
commit 0489c3edf4
27 changed files with 2903 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
NR_OF_CPUS = 2
INC_DIR += $(REP_DIR)/src/bootstrap/spec/panda
INC_DIR += $(REP_DIR)/src/include
SRC_CC += bootstrap/spec/arm/cpu.cc
SRC_CC += bootstrap/spec/arm/cortex_a9_mmu.cc
SRC_CC += bootstrap/spec/arm/gicv2.cc
SRC_CC += bootstrap/spec/panda/platform.cc
SRC_CC += bootstrap/spec/arm/arm_v7_cpu.cc
SRC_CC += hw/spec/32bit/memory_map.cc
SRC_S += bootstrap/spec/arm/crt0.s
CC_MARCH = -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc
vpath bootstrap/spec/panda/platform.cc $(REP_DIR)/src

View File

@@ -0,0 +1,20 @@
#
# \brief Build config for Genodes core process
# \author Stefan Kalkowski
# \author Martin Stein
# \date 2012-10-04
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/spec/panda
INC_DIR += $(REP_DIR)/src/include
# add C++ sources
SRC_CC += platform_services.cc
NR_OF_CPUS += 2
CC_MARCH = -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp
# include less specific configuration
include $(BASE_DIR)/../base-hw/lib/mk/spec/cortex_a9/core-hw.inc

11
mk/spec/panda.mk Normal file
View File

@@ -0,0 +1,11 @@
#
# Enable peripherals of the platform
#
SPECS += omap4 usb panda gpio framebuffer
#
# Pull in CPU specifics
#
SPECS += arm_v7a
include $(BASE_DIR)/mk/spec/arm_v7a.mk

View File

@@ -0,0 +1,41 @@
BOARD = panda
content: src/include src/core src/lib src/timer lib/mk LICENSE
src/include src/core src/lib src/timer lib/mk:
mkdir -p $@
cp -r $(GENODE_DIR)/repos/base/$@/* $@
cp -r $(GENODE_DIR)/repos/base-hw/$@/* $@
LICENSE:
cp $(GENODE_DIR)/LICENSE $@
content: lib/mk/spec/arm_v7/bootstrap-hw-panda.mk lib/mk/spec/arm_v7/core-hw-panda.mk
lib/mk/spec/arm_v7/bootstrap-hw-panda.mk lib/mk/spec/arm_v7/core-hw-panda.mk: lib/mk
cp $(REP_DIR)/$@ $@
content: etc/specs.conf src/bootstrap
etc/specs.conf src/bootstrap:
mkdir -p etc
mkdir -p src
cp -r $(GENODE_DIR)/repos/base-hw/$@ $@
content: generalize_target_names remove_other_board_libs
generalize_target_names: lib/mk src/lib src/timer
for spec in arm riscv x86_64; do \
mv lib/mk/spec/$$spec/ld-hw.mk lib/mk/spec/$$spec/ld.mk; \
done;
sed -i "s/ld-hw/ld/" src/lib/ld/hw/target.mk
sed -i "s/hw_timer_drv/timer/" src/timer/hw/target.mk
remove_other_board_libs: lib/mk
find lib/mk/spec -name core-hw-*.mk -o -name bootstrap-hw-*.mk |\
grep -v "hw-$(BOARD).mk" | xargs rm -rf
content: enable_board_spec
enable_board_spec: etc/specs.conf
echo "SPECS += panda" >> etc/specs.conf

View File

@@ -0,0 +1 @@
2020-03-23-b 841ce3bb426e5685d1c08612acdd78b70eb5e7b8

View File

@@ -0,0 +1,2 @@
base-hw
base

View File

@@ -0,0 +1,81 @@
/*
* \brief Pandaboard specific definitions
* \author Stefan Kalkowski
* \date 2017-02-20
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__BOOTSTRAP__SPEC__PANDA__BOARD_H_
#define _SRC__BOOTSTRAP__SPEC__PANDA__BOARD_H_
#include <hw/spec/arm/panda_board.h>
#include <spec/arm/cortex_a9_page_table.h>
#include <spec/arm/cpu.h>
#include <hw/spec/arm/gicv2.h>
namespace Board {
using namespace Hw::Panda_board;
using Pic = Hw::Gicv2;
static constexpr bool NON_SECURE = false;
class L2_cache;
}
namespace Bootstrap { struct Actlr; }
struct Bootstrap::Actlr
{
static void enable_smp()
{
using namespace Board;
call_panda_firmware(CPU_ACTLR_SMP_BIT_RAISE, 0);
}
static void disable_smp() { /* not implemented */ }
};
class Board::L2_cache : Hw::Pl310
{
private:
unsigned long _init_value()
{
Aux::access_t v = 0;
Aux::Associativity::set(v, Aux::Associativity::WAY_16);
Aux::Way_size::set(v, Aux::Way_size::KB_64);
Aux::Share_override::set(v, true);
Aux::Replacement_policy::set(v, Aux::Replacement_policy::PRAND);
Aux::Ns_lockdown::set(v, true);
Aux::Ns_irq_ctrl::set(v, true);
Aux::Data_prefetch::set(v, true);
Aux::Inst_prefetch::set(v, true);
Aux::Early_bresp::set(v, true);
return v;
}
public:
L2_cache(Genode::addr_t mmio) : Hw::Pl310(mmio) {
call_panda_firmware(L2_CACHE_AUX_REG, _init_value()); }
using Hw::Pl310::invalidate;
void enable()
{
call_panda_firmware(L2_CACHE_ENABLE_REG, 1);
Pl310::mask_interrupts();
}
void disable() {
call_panda_firmware(L2_CACHE_ENABLE_REG, 0); }
};
#endif /* _SRC__BOOTSTRAP__SPEC__PANDA__BOARD_H_ */

View File

@@ -0,0 +1,50 @@
/*
* \brief Parts of platform that are specific to Pandaboard
* \author Stefan Kalkowski
* \date 2017-01-30
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <platform.h>
using namespace Board;
Bootstrap::Platform::Board::Board()
: early_ram_regions(Memory_region { RAM_0_BASE, RAM_0_SIZE }),
core_mmio(Memory_region { CORTEX_A9_PRIVATE_MEM_BASE,
CORTEX_A9_PRIVATE_MEM_SIZE },
Memory_region { TL16C750_3_MMIO_BASE,
TL16C750_MMIO_SIZE },
Memory_region { PL310_MMIO_BASE,
PL310_MMIO_SIZE }) { }
bool Board::Cpu::errata(Board::Cpu::Errata) { return false; }
void Board::Cpu::wake_up_all_cpus(void * const ip)
{
struct Wakeup_generator : Genode::Mmio
{
struct Aux_core_boot_0 : Register<0x800, 32> {
struct Cpu1_status : Bitfield<2, 2> { }; };
struct Aux_core_boot_1 : Register<0x804, 32> { };
Wakeup_generator(void * const ip) : Mmio(CORTEX_A9_WUGEN_MMIO_BASE)
{
write<Aux_core_boot_1>((Genode::addr_t)ip);
write<Aux_core_boot_0::Cpu1_status>(1);
}
};
Wakeup_generator wgen(ip);
asm volatile("dsb\n"
"sev\n");
}

View File

@@ -0,0 +1,54 @@
/*
* \brief Board driver for core on pandaboard
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2014-06-02
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _CORE__SPEC__PANDA__BOARD_H_
#define _CORE__SPEC__PANDA__BOARD_H_
#include <hw/spec/arm/gicv2.h>
#include <hw/spec/arm/panda_board.h>
#include <spec/arm/cortex_a9_private_timer.h>
namespace Board {
using namespace Hw::Panda_board;
using Pic = Hw::Gicv2;
class L2_cache : public Hw::Pl310
{
private:
unsigned long _debug_value()
{
Debug::access_t v = 0;
Debug::Dwb::set(v, 1);
Debug::Dcl::set(v, 1);
return v;
}
public:
L2_cache(Genode::addr_t mmio) : Hw::Pl310(mmio) { }
void clean_invalidate()
{
using namespace Hw;
call_panda_firmware(L2_CACHE_SET_DEBUG_REG, _debug_value());
Pl310::clean_invalidate();
call_panda_firmware(L2_CACHE_SET_DEBUG_REG, 0);
}
};
L2_cache & l2_cache();
}
#endif /* _CORE__SPEC__PANDA__BOARD_H_ */

View File

@@ -0,0 +1,129 @@
/*
* \brief Display controller
* \author Martin Stein
* \author Norman Feske
* \date 2012-06-11
*/
/*
* Copyright (C) 2009-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DISPC_H_
#define _DISPC_H_
/* Genode includes */
#include <util/mmio.h>
struct Dispc : Genode::Mmio
{
/**
* Configures the display controller module for outputs LCD 1 and TV
*/
struct Control1 : Register<0x40, 32>
{
struct Lcd_enable : Bitfield<0, 1> { };
struct Tv_enable : Bitfield<1, 1> { };
struct Go_lcd : Bitfield<5, 1>
{
enum { HW_UPDATE_DONE = 0x0, /* set by HW after updating */
REQUEST_HW_UPDATE = 0x1 }; /* must be set by user */
};
struct Go_tv : Bitfield<6, 1>
{
enum { HW_UPDATE_DONE = 0x0, /* set by HW after updating */
REQUEST_HW_UPDATE = 0x1 }; /* must be set by user */
};
};
/**
* Configures the display controller module for outputs LCD 1 and TV
*/
struct Config1 : Register<0x44, 32>
{
/**
* Loading of palette/gamma table
*/
struct Load_mode : Bitfield<1, 2>
{
enum { DATA_EVERY_FRAME = 0x2, };
};
};
struct Size_tv : Register<0x78, 32>
{
struct Width : Bitfield<0, 11> { };
struct Height : Bitfield<16, 11> { };
};
struct Size_lcd : Register<0x7c, 32>
{
struct Width : Bitfield<0, 11> { };
struct Height : Bitfield<16, 11> { };
};
/**
* Configures base address of the graphics buffer
*/
struct Gfx_ba0 : Register<0x80, 32> { };
struct Gfx_ba1 : Register<0x84, 32> { };
/**
* Configures the size of the graphics window
*/
struct Gfx_size : Register<0x8c, 32>
{
struct Sizex : Bitfield<0,11> { };
struct Sizey : Bitfield<16,11> { };
};
/**
* Configures the graphics attributes
*/
struct Gfx_attributes : Register<0xa0, 32>
{
struct Enable : Bitfield<0, 1> { };
struct Format : Bitfield<1, 5>
{
enum { RGB16 = 0x6,
ARGB32 = 0xc,
RGBA32 = 0xd };
};
/**
* Select GFX channel output
*/
struct Channelout : Bitfield<8, 1>
{
enum { TV = 0x1 };
};
struct Channelout2 : Bitfield<30, 2>
{
enum { PRIMARY_LCD = 0 };
};
};
struct Global_buffer : Register<0x800, 32> { };
struct Divisor : Register<0x804, 32>
{
struct Enable : Bitfield<0, 1> { };
struct Lcd : Bitfield<16, 8> { };
};
/**
* Constructor
*
* \param mmio_base base address of DISPC MMIO
*/
Dispc(Genode::addr_t const mmio_base)
:
Mmio(mmio_base)
{ }
};
#endif /* _DISPC_H_ */

View File

@@ -0,0 +1,293 @@
/*
* \brief Frame-buffer driver for the OMAP4430 display-subsystem (HDMI)
* \author Norman Feske
* \author Martin Stein
* \date 2012-06-01
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/attached_io_mem_dataspace.h>
#include <timer_session/connection.h>
#include <util/mmio.h>
/* local includes */
#include <dss.h>
#include <dispc.h>
#include <hdmi.h>
namespace Framebuffer {
using namespace Genode;
class Driver;
}
class Framebuffer::Driver
{
public:
enum Format { FORMAT_RGB565 };
enum Output { OUTPUT_LCD, OUTPUT_HDMI };
private:
enum {
DSS_MMIO_BASE = 0x58000000,
DSS_MMIO_SIZE = 0x00001000,
DISPC_MMIO_BASE = 0x58001000,
DISPC_MMIO_SIZE = 0x00001000,
HDMI_MMIO_BASE = 0x58006000,
HDMI_MMIO_SIZE = 0x00001000,
};
Genode::Env &_env;
bool _init_lcd(addr_t phys_base);
bool _init_hdmi(addr_t phys_base);
struct Timer_delayer : Timer::Connection, Mmio::Delayer
{
Timer_delayer(Genode::Env &env) : Timer::Connection(env) { }
/**
* Implementation of 'Delayer' interface
*/
void usleep(uint64_t us)
{
Timer::Connection::usleep(us);
}
} _delayer { _env };
/* display sub system registers */
Attached_io_mem_dataspace _dss_mmio;
Dss _dss;
/* display controller registers */
Attached_io_mem_dataspace _dispc_mmio;
Dispc _dispc;
/* HDMI controller registers */
Attached_io_mem_dataspace _hdmi_mmio;
Hdmi _hdmi;
size_t _fb_width;
size_t _fb_height;
Format _fb_format;
public:
Driver(Genode::Env &env);
static size_t bytes_per_pixel(Format format)
{
switch (format) {
case FORMAT_RGB565: return 2;
}
return 0;
}
size_t buffer_size(size_t width, size_t height, Format format)
{
return bytes_per_pixel(format)*width*height;
}
bool init(size_t width, size_t height, Format format,
Output output, addr_t phys_base);
};
Framebuffer::Driver::Driver(Genode::Env &env)
:
_env(env),
_dss_mmio(_env, DSS_MMIO_BASE, DSS_MMIO_SIZE),
_dss((addr_t)_dss_mmio.local_addr<void>()),
_dispc_mmio(_env, DISPC_MMIO_BASE, DISPC_MMIO_SIZE),
_dispc((addr_t)_dispc_mmio.local_addr<void>()),
_hdmi_mmio(_env, HDMI_MMIO_BASE, HDMI_MMIO_SIZE),
_hdmi((addr_t)_hdmi_mmio.local_addr<void>()),
_fb_width(0),
_fb_height(0),
_fb_format(FORMAT_RGB565)
{ }
bool Framebuffer::Driver::_init_lcd(Framebuffer::addr_t phys_base)
{
/* disable LCD to allow editing configuration */
_dispc.write<Dispc::Control1::Lcd_enable>(0);
/* set load mode */
_dispc.write<Dispc::Config1::Load_mode>(Dispc::Config1::Load_mode::DATA_EVERY_FRAME);
_dispc.write<Dispc::Size_lcd::Width>(_fb_width - 1);
_dispc.write<Dispc::Size_lcd::Height>(_fb_height - 1);
Dispc::Gfx_attributes::access_t pixel_format = 0;
switch (_fb_format) {
case FORMAT_RGB565: pixel_format = Dispc::Gfx_attributes::Format::RGB16; break;
}
_dispc.write<Dispc::Gfx_attributes::Format>(pixel_format);
_dispc.write<Dispc::Gfx_ba0>(phys_base);
_dispc.write<Dispc::Gfx_ba1>(phys_base);
_dispc.write<Dispc::Gfx_size::Sizex>(_fb_width - 1);
_dispc.write<Dispc::Gfx_size::Sizey>(_fb_height - 1);
_dispc.write<Dispc::Global_buffer>(0x6d2240);
_dispc.write<Dispc::Gfx_attributes::Enable>(1);
_dispc.write<Dispc::Control1::Lcd_enable>(1);
_dispc.write<Dispc::Control1::Go_lcd>(1);
return true;
}
bool Framebuffer::Driver::_init_hdmi(Framebuffer::addr_t phys_base)
{
/* enable display core clock and set divider to 1 */
_dispc.write<Dispc::Divisor::Lcd>(1);
_dispc.write<Dispc::Divisor::Enable>(1);
/* set load mode */
_dispc.write<Dispc::Config1::Load_mode>(Dispc::Config1::Load_mode::DATA_EVERY_FRAME);
_hdmi.write<Hdmi::Video_cfg::Start>(0);
if (!_hdmi.issue_pwr_pll_command(Hdmi::Pwr_ctrl::ALL_OFF, _delayer)) {
error("powering off HDMI timed out");
return false;
}
if (!_hdmi.issue_pwr_pll_command(Hdmi::Pwr_ctrl::BOTH_ON_ALL_CLKS, _delayer)) {
error("powering on HDMI timed out");
return false;
}
if (!_hdmi.reset_pll(_delayer)) {
error("resetting HDMI PLL timed out");
return false;
}
_hdmi.write<Hdmi::Pll_control::Mode>(Hdmi::Pll_control::Mode::MANUAL);
_hdmi.write<Hdmi::Cfg1::Regm>(270);
_hdmi.write<Hdmi::Cfg1::Regn>(15);
_hdmi.write<Hdmi::Cfg2::Highfreq_div_by_2>(0);
_hdmi.write<Hdmi::Cfg2::Refen>(1);
_hdmi.write<Hdmi::Cfg2::Clkinen>(0);
_hdmi.write<Hdmi::Cfg2::Refsel>(3);
_hdmi.write<Hdmi::Cfg2::Freq_divider>(2);
_hdmi.write<Hdmi::Cfg4::Regm2>(1);
_hdmi.write<Hdmi::Cfg4::Regmf>(0x35555);
if (!_hdmi.pll_go(_delayer)) {
error("HDMI PLL GO timed out");
return false;
}
if (!_hdmi.issue_pwr_phy_command(Hdmi::Pwr_ctrl::LDOON, _delayer)) {
error("HDMI Phy power on timed out");
return false;
}
_hdmi.write<Hdmi::Txphy_tx_ctrl::Freqout>(1);
_hdmi.write<Hdmi::Txphy_digital_ctrl>(0xf0000000);
if (!_hdmi.issue_pwr_phy_command(Hdmi::Pwr_ctrl::TXON, _delayer)) {
error("HDMI Txphy power on timed out");
return false;
}
_hdmi.write<Hdmi::Video_timing_h::Bp>(160);
_hdmi.write<Hdmi::Video_timing_h::Fp>(24);
_hdmi.write<Hdmi::Video_timing_h::Sw>(136);
_hdmi.write<Hdmi::Video_timing_v::Bp>(29);
_hdmi.write<Hdmi::Video_timing_v::Fp>(3);
_hdmi.write<Hdmi::Video_timing_v::Sw>(6);
_hdmi.write<Hdmi::Video_cfg::Packing_mode>(Hdmi::Video_cfg::Packing_mode::PACK_24B);
_hdmi.write<Hdmi::Video_size::X>(_fb_width);
_hdmi.write<Hdmi::Video_size::Y>(_fb_height);
_hdmi.write<Hdmi::Video_cfg::Vsp>(0);
_hdmi.write<Hdmi::Video_cfg::Hsp>(0);
_hdmi.write<Hdmi::Video_cfg::Interlacing>(0);
_hdmi.write<Hdmi::Video_cfg::Tm>(1);
_dss.write<Dss::Ctrl::Venc_hdmi_switch>(Dss::Ctrl::Venc_hdmi_switch::HDMI);
_dispc.write<Dispc::Size_tv::Width>(_fb_width - 1);
_dispc.write<Dispc::Size_tv::Height>(_fb_height - 1);
_hdmi.write<Hdmi::Video_cfg::Start>(1);
Dispc::Gfx_attributes::access_t pixel_format = 0;
switch (_fb_format) {
case FORMAT_RGB565: pixel_format = Dispc::Gfx_attributes::Format::RGB16; break;
}
_dispc.write<Dispc::Gfx_attributes::Format>(pixel_format);
_dispc.write<Dispc::Gfx_ba0>(phys_base);
_dispc.write<Dispc::Gfx_ba1>(phys_base);
_dispc.write<Dispc::Gfx_size::Sizex>(_fb_width - 1);
_dispc.write<Dispc::Gfx_size::Sizey>(_fb_height - 1);
_dispc.write<Dispc::Global_buffer>(0x6d2240);
_dispc.write<Dispc::Gfx_attributes::Enable>(1);
_dispc.write<Dispc::Gfx_attributes::Channelout>(Dispc::Gfx_attributes::Channelout::TV);
_dispc.write<Dispc::Gfx_attributes::Channelout2>(Dispc::Gfx_attributes::Channelout2::PRIMARY_LCD);
_dispc.write<Dispc::Control1::Tv_enable>(1);
_dispc.write<Dispc::Control1::Go_tv>(1);
try {
_dispc.wait_for(_delayer, Dispc::Control1::Go_tv::Equal(Dispc::Control1::Go_tv::HW_UPDATE_DONE));
}
catch (Dispc::Polling_timeout) {
error("Go_tv timed out");
return false;
}
return true;
}
bool Framebuffer::Driver::init(size_t width, size_t height,
Framebuffer::Driver::Format format,
Output output,
Framebuffer::addr_t phys_base)
{
_fb_width = width;
_fb_height = height;
_fb_format = format;
bool ret = false;
switch (output) {
case OUTPUT_LCD:
ret = _init_lcd(phys_base);
break;
case OUTPUT_HDMI:
ret = _init_hdmi(phys_base);
break;
default:
error("unknown output ", (int)output, " specified");
}
return ret;
}

View File

@@ -0,0 +1,29 @@
/*
* \brief General display subsystem registers
* \author Norman Feske
* \date 2012-06-11
*/
#ifndef _DSS_H_
#define _DSS_H_
/* Genode includes */
#include <util/mmio.h>
struct Dss : Genode::Mmio
{
Dss(Genode::addr_t const mmio_base) : Genode::Mmio(mmio_base) { }
struct Sysstatus : Register<0x14, 32> { };
struct Ctrl : Register<0x40, 32>
{
struct Venc_hdmi_switch : Bitfield<15, 1>
{
enum { HDMI = 1 };
};
};
struct Status : Register<0x5c, 32> { };
};
#endif /* _DSS_H_ */

View File

@@ -0,0 +1,197 @@
/*
* \brief HDMI subsystem registers
* \author Norman Feske
* \date 2012-06-11
*/
/*
* Copyright (C) 2009-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DRIVERS__FRAMEBUFFER__SPEC__OMAP4__HDMI_H_
#define _DRIVERS__FRAMEBUFFER__SPEC__OMAP4__HDMI_H_
/* Genode includes */
#include <util/mmio.h>
struct Hdmi : Genode::Mmio
{
struct Pwr_ctrl : Register<0x40, 32>
{
enum Pll_cmd_type { ALL_OFF = 0,
BOTH_ON_ALL_CLKS = 2, };
struct Pll_cmd : Bitfield<2, 2> { };
struct Pll_status : Bitfield<0, 2> { };
enum Phy_cmd_type { LDOON = 1,
TXON = 2 };
struct Phy_cmd : Bitfield<6, 2> { };
struct Phy_status : Bitfield<4, 2> { };
};
struct Video_cfg : Register<0x50, 32>
{
struct Start : Bitfield<31, 1> { };
struct Packing_mode : Bitfield<8, 3>
{
enum { PACK_24B = 1 };
};
struct Vsp : Bitfield<7, 1> { };
struct Hsp : Bitfield<6, 1> { };
struct Interlacing : Bitfield<3, 1> { };
struct Tm : Bitfield<0, 2> { };
};
struct Video_size : Register<0x60, 32>
{
struct X : Bitfield<0, 16> { };
struct Y : Bitfield<16, 16> { };
};
struct Video_timing_h : Register<0x68, 32>
{
struct Bp : Bitfield<20, 12> { };
struct Fp : Bitfield<8, 12> { };
struct Sw : Bitfield<0, 8> { };
};
struct Video_timing_v : Register<0x6c, 32>
{
struct Bp : Bitfield<20, 12> { };
struct Fp : Bitfield<8, 12> { };
struct Sw : Bitfield<0, 8> { };
};
/**
* \return true on success
*/
bool issue_pwr_pll_command(Pwr_ctrl::Pll_cmd_type cmd, Delayer &delayer)
{
write<Pwr_ctrl::Pll_cmd>(cmd);
try {
wait_for(delayer, Pwr_ctrl::Pll_status::Equal(cmd));
}
catch (Polling_timeout) {
Genode::error("Pwr_ctrl::Pll_cmd failed");
return false;
}
return true;
}
bool issue_pwr_phy_command(Pwr_ctrl::Phy_cmd_type cmd, Delayer &delayer)
{
write<Pwr_ctrl::Phy_cmd>(cmd);
try {
wait_for(delayer, Pwr_ctrl::Phy_status::Equal(cmd));
}
catch (Polling_timeout) {
Genode::error("unexpected Pwr_ctrl::Phy_status");
return false;
}
return true;
}
struct Pll_control : Register<0x200, 32>
{
struct Mode : Bitfield<0, 1>
{
enum { MANUAL = 0 };
};
struct Reset : Bitfield<3, 1> { };
};
struct Pll_status : Register<0x204, 32>
{
struct Reset_done : Bitfield<0, 1> { };
struct Pll_locked : Bitfield<1, 1> { };
};
bool wait_until_pll_locked(Delayer &delayer)
{
try {
wait_for(delayer, Pll_status::Pll_locked::Equal(1));
}
catch (Polling_timeout) {
Genode::error("Pll_locked::Pll_locked unexpectedly not set");
return false;
}
return true;
}
struct Pll_go : Register<0x208, 32>
{
struct Go : Bitfield<0, 1> { };
};
bool pll_go(Delayer &delayer)
{
write<Pll_go::Go>(1);
/* wait for PLL_GO bit change and the PLL reaching locked state */
try {
wait_for(delayer, Pll_go::Go::Equal(1));
}
catch (Polling_timeout) {
Genode::error("Pll_go::Go unexpectedly not set");
return false;
}
return wait_until_pll_locked(delayer);
}
struct Cfg1 : Register<0x20c, 32>
{
struct Regm : Bitfield<9, 12> { };
struct Regn : Bitfield<1, 8> { };
};
struct Cfg2 : Register<0x210, 32>
{
struct Highfreq_div_by_2 : Bitfield<12, 1> { };
struct Refen : Bitfield<13, 1> { };
struct Clkinen : Bitfield<14, 1> { };
struct Refsel : Bitfield<21, 2> { };
struct Freq_divider : Bitfield<1, 3> { };
};
struct Cfg4 : Register<0x220, 32>
{
struct Regm2 : Bitfield<18, 7> { };
struct Regmf : Bitfield<0, 18> { };
};
bool reset_pll(Delayer &delayer)
{
write<Pll_control::Reset>(0);
try {
wait_for(delayer, Pll_status::Reset_done::Equal(1));
}
catch (Polling_timeout) {
Genode::error("Pll_status::Reset_done unexpectedly not set");
return false;
}
return true;
};
struct Txphy_tx_ctrl : Register<0x300, 32>
{
struct Freqout : Bitfield<30, 2> { };
};
struct Txphy_digital_ctrl : Register<0x304, 32> { };
Hdmi(Genode::addr_t const mmio_base) : Mmio(mmio_base) { }
};
#endif /* _DRIVERS__FRAMEBUFFER__SPEC__OMAP4__HDMI_H_ */

View File

@@ -0,0 +1,207 @@
/*
* \brief Frame-buffer driver for the OMAP4430 display-subsystem (HDMI)
* \author Norman Feske
* \date 2012-06-21
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/log.h>
#include <framebuffer_session/framebuffer_session.h>
#include <dataspace/client.h>
#include <blit/blit.h>
#include <os/static_root.h>
#include <timer_session/connection.h>
/* local includes */
#include <driver.h>
namespace Framebuffer {
using namespace Genode;
class Session_component;
};
class Framebuffer::Session_component : public Genode::Rpc_object<Framebuffer::Session>
{
private:
/*
* Noncopyable
*/
Session_component(Session_component const &);
Session_component &operator = (Session_component const &);
size_t _width;
size_t _height;
bool _buffered;
Mode _mode { };
Driver::Format _format;
size_t _size;
/* dataspace uses a back buffer (if '_buffered' is true) */
Genode::Dataspace_capability _bb_ds;
void *_bb_addr;
/* dataspace of physical frame buffer */
Genode::Dataspace_capability _fb_ds;
void *_fb_addr;
Signal_context_capability _sync_sigh { };
Timer::Connection _timer;
/**
* Convert Driver::Format to Framebuffer::Mode::Format
*/
static Mode::Format _convert_format(Driver::Format driver_format)
{
switch (driver_format) {
case Driver::FORMAT_RGB565: return Mode::RGB565;
}
return Mode::INVALID;
}
void _refresh_buffered(int x, int y, int w, int h)
{
Mode _mode = mode();
/* clip specified coordinates against screen boundaries */
int x2 = min(x + w - 1, (int)_mode.width() - 1),
y2 = min(y + h - 1, (int)_mode.height() - 1);
int x1 = max(x, 0),
y1 = max(y, 0);
if (x1 > x2 || y1 > y2) return;
int bypp = _mode.bytes_per_pixel();
/* copy pixels from back buffer to physical frame buffer */
char *src = (char *)_bb_addr + bypp*(_mode.width()*y1 + x1),
*dst = (char *)_fb_addr + bypp*(_mode.width()*y1 + x1);
blit(src, bypp*_mode.width(), dst, bypp*_mode.width(),
bypp*(x2 - x1 + 1), y2 - y1 + 1);
}
public:
Session_component(Genode::Env &env, Driver &driver, size_t width, size_t height,
Driver::Output output, bool buffered)
: _width(width),
_height(height),
_buffered(buffered),
_format(Driver::FORMAT_RGB565),
_size(driver.buffer_size(width, height, _format)),
_bb_ds(buffered ? env.ram().alloc(_size)
: Genode::Ram_dataspace_capability()),
_bb_addr(buffered ? (void*)env.rm().attach(_bb_ds) : 0),
_fb_ds(env.ram().alloc(_size, WRITE_COMBINED)),
_fb_addr((void*)env.rm().attach(_fb_ds)),
_timer(env)
{
if (!driver.init(width, height, _format, output,
Dataspace_client(_fb_ds).phys_addr())) {
error("Could not initialize display");
struct Could_not_initialize_display : Exception { };
throw Could_not_initialize_display();
}
Genode::log("using ", width, "x", height,
output == Driver::OUTPUT_HDMI ? " HDMI" : " LCD");
}
/************************************
** Framebuffer::Session interface **
************************************/
Dataspace_capability dataspace() override
{
return _buffered ? _bb_ds : _fb_ds;
}
Mode mode() const override
{
return Mode(_width,
_height,
_convert_format(_format));
}
void mode_sigh(Genode::Signal_context_capability) override { }
void sync_sigh(Genode::Signal_context_capability sigh) override
{
_sync_sigh = sigh;
_timer.sigh(_sync_sigh);
_timer.trigger_periodic(10*1000);
}
void refresh(int x, int y, int w, int h) override
{
if (_buffered)
_refresh_buffered(x, y, w, h);
if (_sync_sigh.valid())
Signal_transmitter(_sync_sigh).submit();
}
};
template <typename T>
static T config_attribute(Genode::Xml_node node, char const *attr_name, T const &default_value)
{
return node.attribute_value(attr_name, default_value);
}
static Framebuffer::Driver::Output config_output(Genode::Xml_node node,
Framebuffer::Driver::Output default_value)
{
Framebuffer::Driver::Output value = default_value;
try {
Genode::String<8> output;
node.attribute("output").value(&output);
if (output == "LCD") { value = Framebuffer::Driver::OUTPUT_LCD; }
} catch (...) { }
return value;
}
struct Main
{
Genode::Env &_env;
Genode::Entrypoint &_ep;
Genode::Attached_rom_dataspace _config { _env, "config" };
Framebuffer::Driver _driver { _env };
Framebuffer::Session_component _fb_session { _env, _driver,
config_attribute(_config.xml(), "width", 1024u),
config_attribute(_config.xml(), "height", 768u),
config_output(_config.xml(), Framebuffer::Driver::OUTPUT_HDMI),
config_attribute(_config.xml(), "buffered", false),
};
Genode::Static_root<Framebuffer::Session> _fb_root { _ep.manage(_fb_session) };
Main(Genode::Env &env) : _env(env), _ep(_env.ep())
{
/* announce service */
_env.parent().announce(_ep.manage(_fb_root));
}
};
void Component::construct(Genode::Env &env) { static Main main(env); }

View File

@@ -0,0 +1,15 @@
#
# \brief Framebuffer driver specific for OMAP44xx systems
# \author Martin Stein
# \date 2012-05-02
#
TARGET = omap4_fb_drv
REQUIRES = arm_v7
SRC_CC = main.cc
LIBS = base blit
INC_DIR += $(PRG_DIR)
vpath main.cc $(PRG_DIR)
CC_CXX_WARN_STRICT =

View File

@@ -0,0 +1,272 @@
/*
* \brief Gpio driver for the OMAP4
* \author Ivan Loskutov <ivan.loskutov@ksyslabs.org>
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \date 2012-06-23
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DRIVERS__GPIO__SPEC__OMAP4__DRIVER_H_
#define _DRIVERS__GPIO__SPEC__OMAP4__DRIVER_H_
/* Genode includes */
#include <gpio/driver.h>
#include <irq_session/connection.h>
#include <timer_session/connection.h>
/* local includes */
#include "gpio.h"
class Omap4_driver : public Gpio::Driver
{
private:
enum {
PIN_SHIFT = 5,
MAX_BANKS = 6,
MAX_PINS = 32
};
enum {
GPIO1_MMIO_BASE = 0x4a310000,
GPIO1_MMIO_SIZE = 0x1000,
GPIO1_IRQ = 29 + 32,
GPIO2_MMIO_BASE = 0x48055000,
GPIO2_MMIO_SIZE = 0x1000,
GPIO2_IRQ = 30 + 32,
GPIO3_MMIO_BASE = 0x48057000,
GPIO3_MMIO_SIZE = 0x1000,
GPIO3_IRQ = 31 + 32,
GPIO4_MMIO_BASE = 0x48059000,
GPIO4_MMIO_SIZE = 0x1000,
GPIO4_IRQ = 32 + 32,
GPIO5_MMIO_BASE = 0x4805b000,
GPIO5_MMIO_SIZE = 0x1000,
GPIO5_IRQ = 33 + 32,
GPIO6_MMIO_BASE = 0x4805d000,
GPIO6_MMIO_SIZE = 0x1000,
GPIO6_IRQ = 34 + 32,
};
class Gpio_bank
{
private:
Gpio_reg _reg;
Genode::Irq_connection _irq;
Genode::Signal_handler<Gpio_bank> _dispatcher;
Genode::Signal_context_capability _sig_cap[MAX_PINS];
bool _irq_enabled[MAX_PINS];
void _handle()
{
_reg.write<Gpio_reg::Irqstatus_0>(0xffffffff);
unsigned long status = _reg.read<Gpio_reg::Irqstatus_0>();
for(unsigned i = 0; i < MAX_PINS; i++) {
if ((status & (1 << i)) && _irq_enabled[i] &&
_sig_cap[i].valid())
Genode::Signal_transmitter(_sig_cap[i]).submit();
}
_irq.ack_irq();
}
public:
Gpio_bank(Genode::Env &env,
Genode::addr_t base, Genode::size_t size,
unsigned irq)
: _reg(env, base, size), _irq(env, irq),
_dispatcher(env.ep(), *this, &Gpio_bank::_handle)
{
for (unsigned i = 0; i < MAX_PINS; i++)
_irq_enabled[i] = false;
_irq.sigh(_dispatcher);
_irq.ack_irq();
}
Gpio_reg* regs() { return &_reg; }
void irq(int pin, bool enable)
{
if (enable) {
_reg.write<Gpio_reg::Irqstatus_0>(1 << pin);
_reg.write<Gpio_reg::Irqstatus_set_0>(1 << pin);
}
else
_reg.write<Gpio_reg::Irqstatus_clr_0>(1 << pin);
_irq_enabled[pin] = enable;
}
void ack_irq(int) { Genode::warning(__func__, " not implemented"); }
void sigh(int pin, Genode::Signal_context_capability cap) {
_sig_cap[pin] = cap; }
};
Gpio_bank _gpio_bank_0;
Gpio_bank _gpio_bank_1;
Gpio_bank _gpio_bank_2;
Gpio_bank _gpio_bank_3;
Gpio_bank _gpio_bank_4;
Gpio_bank _gpio_bank_5;
Gpio_bank *_gpio_bank(int gpio)
{
switch (gpio >> PIN_SHIFT) {
case 0:
return &_gpio_bank_0;
case 1:
return &_gpio_bank_1;
case 2:
return &_gpio_bank_2;
case 3:
return &_gpio_bank_3;
case 4:
return &_gpio_bank_4;
case 5:
return &_gpio_bank_5;
}
Genode::error("no Gpio_bank for pin ", gpio, " available");
return 0;
}
int _gpio_index(int gpio) { return gpio & 0x1f; }
Omap4_driver(Genode::Env &env)
:
_gpio_bank_0(env, GPIO1_MMIO_BASE, GPIO1_MMIO_SIZE, GPIO1_IRQ),
_gpio_bank_1(env, GPIO2_MMIO_BASE, GPIO2_MMIO_SIZE, GPIO2_IRQ),
_gpio_bank_2(env, GPIO3_MMIO_BASE, GPIO3_MMIO_SIZE, GPIO3_IRQ),
_gpio_bank_3(env, GPIO4_MMIO_BASE, GPIO4_MMIO_SIZE, GPIO4_IRQ),
_gpio_bank_4(env, GPIO5_MMIO_BASE, GPIO5_MMIO_SIZE, GPIO5_IRQ),
_gpio_bank_5(env, GPIO6_MMIO_BASE, GPIO6_MMIO_SIZE, GPIO6_IRQ)
{ }
public:
static Omap4_driver& factory(Genode::Env &env);
/******************************
** Gpio::Driver interface **
******************************/
void direction(unsigned gpio, bool input) override
{
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Oe>(input ? 1 : 0, _gpio_index(gpio));
}
void write(unsigned gpio, bool level) override
{
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
if (level)
gpio_reg->write<Gpio_reg::Setdataout>(1 << _gpio_index(gpio));
else
gpio_reg->write<Gpio_reg::Cleardataout>(1 << _gpio_index(gpio));
}
bool read(unsigned gpio) override
{
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
return gpio_reg->read<Gpio_reg::Datain>(_gpio_index(gpio));
}
void debounce_enable(unsigned gpio, bool enable) override
{
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Debounceenable>(enable ? 1 : 0,
_gpio_index(gpio));
}
void debounce_time(unsigned gpio, unsigned long us) override
{
unsigned char debounce;
if (us < 32)
debounce = 0x01;
else if (us > 7936)
debounce = 0xff;
else
debounce = (us / 0x1f) - 1;
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Debouncingtime::Time>(debounce);
}
void falling_detect(unsigned gpio) override
{
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Leveldetect0> (0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Leveldetect1> (0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Fallingdetect>(1, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Risingdetect> (0, _gpio_index(gpio));
}
void rising_detect(unsigned gpio) override
{
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Leveldetect0> (0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Leveldetect1> (0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Fallingdetect>(0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Risingdetect> (1, _gpio_index(gpio));
}
void high_detect(unsigned gpio) override
{
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Leveldetect0> (0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Leveldetect1> (1, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Fallingdetect>(0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Risingdetect> (0, _gpio_index(gpio));
}
void low_detect(unsigned gpio) override
{
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Leveldetect0> (1, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Leveldetect1> (0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Fallingdetect>(0, _gpio_index(gpio));
gpio_reg->write<Gpio_reg::Risingdetect> (0, _gpio_index(gpio));
}
void irq_enable(unsigned gpio, bool enable) override
{
_gpio_bank(gpio)->irq(_gpio_index(gpio), enable);
}
void ack_irq(unsigned gpio) override
{
_gpio_bank(gpio)->ack_irq(_gpio_index(gpio));
}
void register_signal(unsigned gpio,
Genode::Signal_context_capability cap) override
{
_gpio_bank(gpio)->sigh(_gpio_index(gpio), cap); }
void unregister_signal(unsigned gpio) override
{
Genode::Signal_context_capability cap;
_gpio_bank(gpio)->sigh(_gpio_index(gpio), cap);
}
bool gpio_valid(unsigned gpio) override { return gpio < (MAX_PINS*MAX_BANKS); }
};
#endif /* _DRIVERS__GPIO__SPEC__OMAP4__DRIVER_H_ */

View File

@@ -0,0 +1,50 @@
/*
* \brief OMAP4 GPIO definitions
* \author Ivan Loskutov <ivan.loskutov@ksyslabs.org>
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \date 2012-06-23
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DRIVERS__GPIO__SPEC__OMAP4__GPIO_H_
#define _DRIVERS__GPIO__SPEC__OMAP4__GPIO_H_
/* Genode includes */
#include <base/attached_io_mem_dataspace.h>
#include <util/mmio.h>
struct Gpio_reg : Genode::Attached_io_mem_dataspace, Genode::Mmio
{
Gpio_reg(Genode::Env &env,
Genode::addr_t const mmio_base,
Genode::size_t const mmio_size)
: Genode::Attached_io_mem_dataspace(env, mmio_base, mmio_size),
Genode::Mmio((Genode::addr_t)local_addr<void>()) { }
struct Oe : Register_array<0x134, 32, 32, 1> {};
struct Irqstatus_0 : Register<0x02c, 32> {};
struct Irqstatus_set_0 : Register<0x034, 32> {};
struct Irqstatus_clr_0 : Register<0x03c, 32> {};
struct Ctrl : Register<0x130, 32> {};
struct Leveldetect0 : Register_array<0x140, 32, 32, 1> {};
struct Leveldetect1 : Register_array<0x144, 32, 32, 1> {};
struct Risingdetect : Register_array<0x148, 32, 32, 1> {};
struct Fallingdetect : Register_array<0x14c, 32, 32, 1> {};
struct Debounceenable : Register_array<0x150, 32, 32, 1> {};
struct Debouncingtime : Register<0x154, 32>
{
struct Time : Bitfield<0, 8> {};
};
struct Cleardataout : Register<0x190, 32> {};
struct Setdataout : Register<0x194, 32> {};
struct Datain : Register_array<0x138, 32, 32, 1> {};
};
#endif /* _DRIVERS__GPIO__SPEC__OMAP4__GPIO_H_ */

View File

@@ -0,0 +1,64 @@
/*
* \brief Gpio driver for the OMAP4
* \author Ivan Loskutov <ivan.loskutov@ksyslabs.org>
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \date 2012-06-23
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/log.h>
#include <base/heap.h>
#include <gpio/component.h>
#include <gpio/config.h>
/* local includes */
#include <driver.h>
Omap4_driver& Omap4_driver::factory(Genode::Env &env)
{
static Omap4_driver driver(env);
return driver;
}
struct Main
{
Genode::Env &env;
Genode::Sliced_heap sliced_heap;
Omap4_driver &driver;
Gpio::Root root;
Genode::Attached_rom_dataspace config_rom { env, "config" };
Main(Genode::Env &env)
:
env(env),
sliced_heap(env.ram(), env.rm()),
driver(Omap4_driver::factory(env)),
root(&env.ep().rpc_ep(), &sliced_heap, driver)
{
using namespace Genode;
log("--- omap4 gpio driver ---");
Gpio::process_config(config_rom.xml(), driver);
/*
* Announce service
*/
env.parent().announce(env.ep().manage(root));
}
};
void Component::construct(Genode::Env &env) { static Main main(env); }

View File

@@ -0,0 +1,8 @@
TARGET = omap4_gpio_drv
REQUIRES = arm_v7
SRC_CC = main.cc
LIBS = base
INC_DIR += $(PRG_DIR)
vpath main.cc $(PRG_DIR)

View File

@@ -0,0 +1,458 @@
/*
* \brief OMAP4-specific implementation of the Block::Driver interface
* \author Norman Feske
* \date 2012-07-19
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <driver.h>
using namespace Genode;
using namespace Sd_card;
Card_info Driver::_init()
{
Mmio::write<Sysconfig>(0x2015);
Mmio::write<Hctl>(0x0);
_set_bus_power(VOLTAGE_3_0);
if (!_sd_bus_power_on()) {
error("sd_bus_power failed");
}
_disable_irq();
_bus_width(BUS_WIDTH_1);
_delayer.usleep(10*1000);
_stop_clock();
if (!_set_and_enable_clock(CLOCK_DIV_240)) {
error("set_clock failed");
throw Detection_failed();
}
if (!_init_stream()) {
error("sending the initialization stream failed");
throw Detection_failed();
}
Mmio::write<Blk>(0);
_delayer.usleep(1000);
if (!issue_command(Go_idle_state())) {
error("Go_idle_state command failed");
throw Detection_failed();
}
_delayer.usleep(2000);
if (!issue_command(Send_if_cond())) {
error("Send_if_cond command failed");
throw Detection_failed();
}
if (Mmio::read<Rsp10>() != 0x1aa) {
error("unexpected response of Send_if_cond command");
throw Detection_failed();
}
/*
* We need to issue the same Sd_send_op_cond command multiple
* times. The first time, we receive the status information. On
* subsequent attempts, the response tells us that the card is
* busy. Usually, the command is issued twice. We give up if the
* card is not reaching busy state after one second.
*/
int i = 1000;
for (; i > 0; --i) {
if (!issue_command(Sd_send_op_cond(0x18000, true))) {
warning("Sd_send_op_cond command failed");
throw Detection_failed();
}
if (Ocr::Busy::get(Mmio::read<Rsp10>()))
break;
_delayer.usleep(1000);
}
if (i == 0) {
error("Sd_send_op_cond timed out, could no power-on SD card");
throw Detection_failed();
}
Card_info card_info = _detect();
/*
* Switch card to use 4 data signals
*/
if (!issue_command(Set_bus_width(Set_bus_width::Arg::Bus_width::FOUR_BITS),
card_info.rca())) {
warning("Set_bus_width(FOUR_BITS) command failed");
throw Detection_failed();
}
_bus_width(BUS_WIDTH_4);
_delayer.usleep(10*1000);
_stop_clock();
if (!_set_and_enable_clock(CLOCK_DIV_0)) {
error("set_clock failed");
throw Detection_failed();
}
/* enable IRQs */
Mmio::write<Ie::Tc_enable>(1);
Mmio::write<Ie::Cto_enable>(1);
Mmio::write<Ise::Tc_sigen>(1);
Mmio::write<Ise::Cto_sigen>(1);
return card_info;
}
bool Driver::_wait_for_bre()
{
try { wait_for(Attempts(1000000), Microseconds(0), _delayer,
Pstate::Bre::Equal(1)); }
catch (Polling_timeout) {
try { wait_for(_delayer, Pstate::Bre::Equal(1)); }
catch (Polling_timeout) {
error("Pstate::Bre timed out");
return false;
}
}
return true;
}
bool Driver::_wait_for_bwe()
{
try { wait_for(Attempts(1000000), Microseconds(0), _delayer,
Pstate::Bwe::Equal(1)); }
catch (Polling_timeout) {
try { wait_for(_delayer, Pstate::Bwe::Equal(1)); }
catch (Polling_timeout) {
error("Pstate::Bwe timed out");
return false;
}
}
return true;
}
void Driver::_handle_irq()
{
_irq.ack_irq();
if (!_block_transfer.pending) {
return; }
if (Mmio::read<Stat::Tc>() != 1) {
warning("unexpected interrupt, Stat: ", Hex(Mmio::read<Stat>()));
return;
}
Mmio::write<Stat::Tc>(1);
if (Mmio::read<Stat>() != 0) {
warning("unexpected state ("
"Stat: ", Hex(Mmio::read<Stat>()), " "
"Blen: ", Hex(Mmio::read<Blk::Blen>()), " "
"Nblk: ", Mmio::read<Blk::Nblk>());
return;
}
_block_transfer.pending = false;
ack_packet(_block_transfer.packet, true);
}
bool Driver::_reset_cmd_line()
{
Mmio::write<Sysctl::Src>(1);
/*
* We must poll quickly. If we waited too long until checking the
* bit, the polling would be infinite. Apparently the hardware
* depends on the timing here.
*/
try { wait_for(Attempts(1000), Microseconds(0), _delayer,
Sysctl::Src::Equal(1)); }
catch (Polling_timeout) {
error("reset of cmd line timed out (src != 1)");
return false;
}
try { wait_for(Attempts(1000), Microseconds(0), _delayer,
Sysctl::Src::Equal(0)); }
catch (Polling_timeout) {
error("reset of cmd line timed out (src != 0)");
return false;
}
return true;
}
void Driver::_disable_irq()
{
Mmio::write<Ise>(0);
Mmio::write<Ie>(0);
Mmio::write<Stat>(~0);
}
void Driver::_bus_width(Bus_width bus_width)
{
switch (bus_width) {
case BUS_WIDTH_1:
Mmio::write<Con::Dw8>(0);
Mmio::write<Hctl::Dtw>(Hctl::Dtw::ONE_BIT);
break;
case BUS_WIDTH_4:
Mmio::write<Con::Dw8>(0);
Mmio::write<Hctl::Dtw>(Hctl::Dtw::FOUR_BITS);
break;
}
}
bool Driver::_sd_bus_power_on()
{
Mmio::write<Hctl::Sdbp>(Hctl::Sdbp::POWER_ON);
try { wait_for(_delayer, Hctl::Sdbp::Equal(1)); }
catch (Polling_timeout) {
error("setting Hctl::Sdbp timed out");
return false;
}
return true;
}
bool Driver::_set_and_enable_clock(enum Clock_divider divider)
{
Mmio::write<Sysctl::Dto>(Sysctl::Dto::TCF_2_POW_27);
switch (divider) {
case CLOCK_DIV_0: Mmio::write<Sysctl::Clkd>(0); break;
case CLOCK_DIV_240: Mmio::write<Sysctl::Clkd>(240); break;
}
Mmio::write<Sysctl::Ice>(1);
/* wait for clock to become stable */
try { wait_for(_delayer, Sysctl::Ics::Equal(1)); }
catch (Polling_timeout) {
error("clock enable timed out");
return false;
}
/* enable clock */
Mmio::write<Sysctl::Ce>(1);
return true;
}
void Driver::_set_bus_power(Voltage voltage)
{
switch (voltage) {
case VOLTAGE_3_0:
Mmio::write<Hctl::Sdvs>(Hctl::Sdvs::VOLTAGE_3_0);
break;
case VOLTAGE_1_8:
Mmio::write<Hctl::Sdvs>(Hctl::Sdvs::VOLTAGE_1_8);
break;
}
Mmio::write<Capa::Vs18>(1);
if (voltage == VOLTAGE_3_0)
Mmio::write<Capa::Vs30>(1);
}
bool Driver::_init_stream()
{
Mmio::write<Ie>(0x307f0033);
/* start initialization sequence */
Mmio::write<Con::Init>(1);
Mmio::write<Cmd>(0);
try { wait_for(Attempts(1000000), Microseconds(0), _delayer,
Stat::Cc::Equal(1)); }
catch (Polling_timeout) {
error("init stream timed out");
return false;
}
/* stop initialization sequence */
Mmio::write<Con::Init>(0);
Mmio::write<Stat>(~0);
Mmio::read<Stat>();
return true;
}
bool Driver::_issue_command(Command_base const &command)
{
try { wait_for(_delayer, Pstate::Cmdi::Equal(0)); }
catch (Polling_timeout) {
error("wait for Pstate::Cmdi timed out");
return false;
}
/* write command argument */
Mmio::write<Arg>(command.arg);
/* assemble command register */
Cmd::access_t cmd = 0;
Cmd::Index::set(cmd, command.index);
if (command.transfer != TRANSFER_NONE) {
Cmd::Dp::set(cmd);
Cmd::Bce::set(cmd);
Cmd::Msbs::set(cmd);
if (command.index == Read_multiple_block::INDEX ||
command.index == Write_multiple_block::INDEX)
{
Cmd::Acen::set(cmd);
}
/* set data-direction bit depending on the command */
bool const read = command.transfer == TRANSFER_READ;
Cmd::Ddir::set(cmd, read ? Cmd::Ddir::READ : Cmd::Ddir::WRITE);
}
Cmd::access_t rsp_type = 0;
switch (command.rsp_type) {
case RESPONSE_NONE: rsp_type = Cmd::Rsp_type::RESPONSE_NONE; break;
case RESPONSE_136_BIT: rsp_type = Cmd::Rsp_type::RESPONSE_136_BIT; break;
case RESPONSE_48_BIT: rsp_type = Cmd::Rsp_type::RESPONSE_48_BIT; break;
case RESPONSE_48_BIT_WITH_BUSY: rsp_type = Cmd::Rsp_type::RESPONSE_48_BIT_WITH_BUSY; break;
}
Cmd::Rsp_type::set(cmd, rsp_type);
/* write command */
Mmio::write<Cmd>(cmd);
bool result = false;
/* wait until command is completed, return false on timeout */
for (unsigned long i = 0; i < 1000*1000; i++) {
Stat::access_t const stat = Mmio::read<Stat>();
if (Stat::Erri::get(stat)) {
warning("SD command error");
if (Stat::Cto::get(stat))
warning("timeout");
_reset_cmd_line();
Mmio::write<Stat::Cc>(~0);
Mmio::read<Stat>();
result = false;
break;
}
if (Stat::Cc::get(stat) == 1) {
result = true;
break;
}
}
/* clear status of command-completed bit */
Mmio::write<Stat::Cc>(1);
Mmio::read<Stat>();
return result;
}
Cid Driver::_read_cid()
{
Cid cid;
cid.raw_0 = Mmio::read<Rsp10>();
cid.raw_1 = Mmio::read<Rsp32>();
cid.raw_2 = Mmio::read<Rsp54>();
cid.raw_3 = Mmio::read<Rsp76>();
return cid;
}
Csd Driver::_read_csd()
{
Csd csd;
csd.csd0 = Mmio::read<Rsp10>();
csd.csd1 = Mmio::read<Rsp32>();
csd.csd2 = Mmio::read<Rsp54>();
csd.csd3 = Mmio::read<Rsp76>();
return csd;
}
Driver::Driver(Env &env)
:
Driver_base(env.ram()),
Attached_mmio(env, MMCHS1_MMIO_BASE, MMCHS1_MMIO_SIZE), _env(env)
{
_irq.sigh(_irq_handler);
_irq.ack_irq();
log("SD card detected");
log("capacity: ", _card_info.capacity_mb(), " MiB");
}
void Driver::read(Block::sector_t block_number,
size_t block_count,
char *buffer,
Block::Packet_descriptor &pkt)
{
if (_block_transfer.pending) {
throw Request_congestion(); }
Mmio::write<Blk::Blen>(_block_size());
Mmio::write<Blk::Nblk>(block_count);
_block_transfer.packet = pkt;
_block_transfer.pending = true;
if (!issue_command(Read_multiple_block(block_number))) {
error("Read_multiple_block failed");
throw Io_error();
}
size_t const num_accesses = block_count * _block_size() /
sizeof(Data::access_t);
Data::access_t *dst = (Data::access_t *)(buffer);
for (size_t i = 0; i < num_accesses; i++) {
if (!_wait_for_bre())
throw Io_error();
*dst++ = Mmio::read<Data>();
}
}
void Driver::write(Block::sector_t block_number,
size_t block_count,
char const *buffer,
Block::Packet_descriptor &pkt)
{
if (_block_transfer.pending) {
throw Request_congestion(); }
Mmio::write<Blk::Blen>(_block_size());
Mmio::write<Blk::Nblk>(block_count);
_block_transfer.packet = pkt;
_block_transfer.pending = true;
if (!issue_command(Write_multiple_block(block_number))) {
error("Write_multiple_block failed");
throw Io_error();
}
size_t const num_accesses = block_count * _block_size() /
sizeof(Data::access_t);
Data::access_t const *src = (Data::access_t const *)(buffer);
for (size_t i = 0; i < num_accesses; i++) {
if (!_wait_for_bwe()) {
throw Io_error(); }
Mmio::write<Data>(*src++);
}
}

View File

@@ -0,0 +1,223 @@
/*
* \brief OMAP4-specific implementation of the Block::Driver interface
* \author Norman Feske
* \date 2012-07-19
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DRIVER_H_
#define _DRIVER_H_
/* Genode includes */
#include <os/attached_mmio.h>
#include <timer_session/connection.h>
#include <irq_session/connection.h>
/* local includes */
#include <driver_base.h>
namespace Sd_card { class Driver; }
class Sd_card::Driver : public Driver_base,
private Attached_mmio
{
private:
enum {
MMCHS1_MMIO_BASE = 0x4809c000,
MMCHS1_MMIO_SIZE = 0x00001000,
HSMMC_IRQ = 115,
};
enum Bus_width { BUS_WIDTH_1, BUS_WIDTH_4 };
enum Clock_divider { CLOCK_DIV_0, CLOCK_DIV_240 };
enum Voltage { VOLTAGE_3_0, VOLTAGE_1_8 };
struct Sysconfig : Register<0x110, 32> { };
struct Con : Register<0x12c, 32>
{
struct Init : Bitfield<1, 1> { };
struct Dw8 : Bitfield<5, 1> { };
};
struct Cmd : Register<0x20c, 32>
{
struct Bce : Bitfield<1, 1> { };
struct Acen : Bitfield<2, 1> { };
struct Msbs : Bitfield<5, 1> { };
struct Index : Bitfield<24, 6> { };
struct Dp : Bitfield<21, 1> { };
struct Rsp_type : Bitfield<16, 2>
{
enum Response { RESPONSE_NONE = 0,
RESPONSE_136_BIT = 1,
RESPONSE_48_BIT = 2,
RESPONSE_48_BIT_WITH_BUSY = 3 };
};
struct Ddir : Bitfield<4, 1>
{
enum { WRITE = 0, READ = 1 };
};
};
struct Blk : Register<0x204, 32>
{
struct Blen : Bitfield<0, 12> { };
struct Nblk : Bitfield<16, 16> { };
};
struct Arg : Register<0x208, 32> { };
struct Rsp10 : Register<0x210, 32> { };
struct Rsp32 : Register<0x214, 32> { };
struct Rsp54 : Register<0x218, 32> { };
struct Rsp76 : Register<0x21c, 32> { };
struct Data : Register<0x220, 32> { };
struct Pstate : Register<0x224, 32>
{
struct Cmdi : Bitfield<0, 1> { };
struct Bwe : Bitfield<10, 1> { };
struct Bre : Bitfield<11, 1> { };
};
struct Hctl : Register<0x228, 32>
{
struct Sdbp : Bitfield<8, 1>
{
enum { POWER_OFF = 0, POWER_ON = 1 };
};
struct Sdvs : Bitfield<9, 3>
{
enum Voltage { VOLTAGE_1_8 = 5,
VOLTAGE_3_0 = 6,
VOLTAGE_3_3 = 7 };
};
struct Dtw : Bitfield<1, 1>
{
enum { ONE_BIT = 0, FOUR_BITS = 1 };
};
};
struct Sysctl : Register<0x22c, 32>
{
struct Ice : Bitfield<0, 1> { };
struct Ics : Bitfield<1, 1> { };
struct Ce : Bitfield<2, 1> { };
struct Clkd : Bitfield<6, 10> { };
struct Src : Bitfield<25, 1> { };
struct Dto : Bitfield<16, 4>
{
enum { TCF_2_POW_27 = 0xe };
};
};
struct Stat : Register<0x230, 32>
{
struct Tc : Bitfield<1, 1> { };
struct Cc : Bitfield<0, 1> { };
struct Erri : Bitfield<15, 1> { };
struct Cto : Bitfield<16, 1> { };
};
struct Ie : Register<0x234, 32>
{
struct Tc_enable : Bitfield<1, 1> { };
struct Cto_enable : Bitfield<16, 1> { };
};
struct Ise : Register<0x238, 32>
{
struct Tc_sigen : Bitfield<1, 1> { };
struct Cto_sigen : Bitfield<16, 1> { };
};
struct Capa : Register<0x240, 32>
{
struct Vs30 : Bitfield<25, 1> { };
struct Vs18 : Bitfield<26, 1> { };
};
struct Block_transfer
{
Block::Packet_descriptor packet { };
bool pending = false;
};
struct Timer_delayer : Timer::Connection, Mmio::Delayer
{
Timer_delayer(Genode::Env &env) : Timer::Connection(env) { }
void usleep(uint64_t us) override { Timer::Connection::usleep(us); }
};
Env &_env;
Block_transfer _block_transfer { };
Timer_delayer _delayer { _env };
Signal_handler<Driver> _irq_handler { _env.ep(), *this, &Driver::_handle_irq };
Irq_connection _irq { _env, HSMMC_IRQ };
Card_info _card_info { _init() };
Card_info _init();
bool _wait_for_bre();
bool _wait_for_bwe();
void _handle_irq();
bool _reset_cmd_line();
void _disable_irq();
void _bus_width(Bus_width bus_width);
bool _sd_bus_power_on();
bool _set_and_enable_clock(enum Clock_divider divider);
void _set_bus_power(Voltage voltage);
bool _init_stream();
void _stop_clock() { Mmio::write<Sysctl::Ce>(0); }
/*********************
** Host_controller **
*********************/
bool _issue_command(Command_base const &command) override;
Cid _read_cid() override;
Csd _read_csd() override;
Card_info card_info() const override { return _card_info; }
unsigned _read_rca() override {
return Send_relative_addr::Response::Rca::get(Mmio::read<Rsp10>()); }
public:
Driver(Env &env);
/*******************
** Block::Driver **
*******************/
void read(Block::sector_t block_number,
size_t block_count,
char *buffer,
Block::Packet_descriptor &pkt) override;
void write(Block::sector_t block_number,
size_t block_count,
char const *buffer,
Block::Packet_descriptor &pkt) override;
};
#endif /* _DRIVER_H_ */

View File

@@ -0,0 +1,9 @@
TARGET = omap4_sd_card_drv
REQUIRES = arm_v7
SRC_CC += main.cc driver.cc
LIBS += base
INC_DIR += $(PRG_DIR) $(BASE_DIR)/../os/src/drivers/sd_card
vpath %.cc $(BASE_DIR)/../os/src/drivers/sd_card
vpath %.cc $(PRG_DIR)

View File

@@ -0,0 +1,301 @@
/*
* \brief EHCI for OMAP4
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
* \date 2012-06-20
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <platform.h>
#include <gpio_session/connection.h>
#include <io_mem_session/connection.h>
#include <util/mmio.h>
#include <lx_emul.h>
#include <linux/platform_data/usb-omap.h>
using namespace Genode;
/**
* Base addresses
*/
enum {
EHCI_BASE = 0x4a064c00,
UHH_BASE = 0x4a064000,
TLL_BASE = 0x4a062000,
SCRM_BASE = 0x4a30a000,
CAM_BASE = 0x4a009000, /* used for L3INIT_CM2 */
};
/**
* Inerrupt numbers
*/
enum { IRQ_EHCI = 109 };
/**
* Resources for platform device
*/
static resource _ehci[] =
{
{ EHCI_BASE, EHCI_BASE + 0x400 - 1, "ehci", IORESOURCE_MEM },
{ IRQ_EHCI, IRQ_EHCI, "ehci-irq", IORESOURCE_IRQ },
};
/**
* Port informations for platform device
*/
static struct ehci_hcd_omap_platform_data _ehci_data;
/**
* Enables USB clocks
*/
struct Clocks : Genode::Mmio
{
Clocks(Genode::addr_t const mmio_base) : Mmio(mmio_base)
{
write<Usb_phy_clk>(0x101);
write<Usb_host_clk>(0x1008002);
write<Usb_tll_clk>(0x1);
}
struct Usb_host_clk : Register<0x358, 32> { };
struct Usb_tll_clk : Register<0x368, 32> { };
struct Usb_phy_clk : Register<0x3e0, 32> { };
template <typename T> void update(unsigned val)
{
typename T::access_t access = read<T>();
access |= val;
write<T>(access);
};
};
/**
* Panda board reference USB clock
*/
struct Aux3 : Genode::Mmio
{
Aux3(addr_t const mmio_base) : Mmio(mmio_base)
{
enable();
}
/* the clock register */
struct Aux3_clk : Register<0x31c, 32>
{
struct Src_select : Bitfield<1, 2> { };
struct Div : Bitfield<16, 4> { enum { DIV_2 = 1 }; };
struct Enable : Bitfield<8, 1> { enum { ON = 1 }; };
};
/* clock source register */
struct Aux_src : Register<0x110, 32, true> { };
void enable()
{
/* select system clock */
write<Aux3_clk::Src_select>(0);
/* set to 19.2 Mhz */
write<Aux3_clk::Div>(Aux3_clk::Div::DIV_2);
/* enable clock */
write<Aux3_clk::Enable>(Aux3_clk::Enable::ON);
/* enable_ext = 1 | enable_int = 1| mode = 0x01 */
write<Aux_src>(0xd);
}
};
/**
* ULPI transceiverless link
*/
struct Tll : Genode::Mmio
{
Tll(addr_t const mmio_base) : Mmio(mmio_base)
{
reset();
}
struct Sys_config : Register<0x10, 32>
{
struct Soft_reset : Bitfield<1, 1> { };
struct Cactivity : Bitfield<8, 1> { };
struct Sidle_mode : Bitfield<3, 2> { };
struct Ena_wakeup : Bitfield<2, 1> { };
};
struct Sys_status : Register<0x14, 32> { };
void reset()
{
write<Sys_config>(0x0);
/* reset */
write<Sys_config::Soft_reset>(0x1);
while(!read<Sys_status>())
msleep(1);
/* disable IDLE, enable wake up, enable auto gating */
write<Sys_config::Cactivity>(1);
write<Sys_config::Sidle_mode>(1);
write<Sys_config::Ena_wakeup>(1);
}
};
/**
* USB high-speed host
*/
struct Uhh : Genode::Mmio
{
Uhh(addr_t const mmio_base) : Mmio(mmio_base)
{
/* diable idle and standby */
write<Sys_config::Idle>(1);
write<Sys_config::Standby>(1);
/* set ports to external phy */
write<Host_config::P1_mode>(0);
write<Host_config::P2_mode>(0);
}
struct Sys_config : Register<0x10, 32>
{
struct Idle : Bitfield<2, 2> { };
struct Standby : Bitfield<4, 2> { };
};
struct Host_config : Register<0x40, 32>
{
struct P1_mode : Bitfield<16, 2> { };
struct P2_mode : Bitfield<18, 2> { };
};
};
/**
* EHCI controller
*/
struct Ehci : Genode::Mmio
{
Ehci(addr_t const mmio_base) : Mmio(mmio_base)
{
write<Cmd>(0);
/* reset */
write<Cmd::Reset>(1);
while(read<Cmd::Reset>())
msleep(1);
}
struct Cmd : Register<0x10, 32>
{
struct Reset : Bitfield<1, 1> { };
};
};
/**
* Initialize the USB controller from scratch, since the boot loader might not
* do it or even disable USB.
*/
static void omap_ehci_init(Genode::Env &env)
{
/* taken from the Panda board manual */
enum { HUB_POWER = 1, HUB_NRESET = 62, ULPI_PHY_TYPE = 182 };
/* SCRM */
Io_mem_connection io_scrm(env, SCRM_BASE, 0x1000);
addr_t scrm_base = (addr_t)env.rm().attach(io_scrm.dataspace());
/* enable reference clock */
Aux3 aux3(scrm_base);
/* init GPIO */
Gpio::Connection gpio_power(env, HUB_POWER);
Gpio::Connection gpio_reset(env, HUB_NRESET);
/* disable the hub power and reset before init */
gpio_power.direction(Gpio::Session::OUT);
gpio_reset.direction(Gpio::Session::OUT);
gpio_power.write(false);
gpio_reset.write(true);
/* enable clocks */
Io_mem_connection io_clock(env, CAM_BASE, 0x1000);
addr_t clock_base = (addr_t)env.rm().attach(io_clock.dataspace());
Clocks c(clock_base);
/* reset TLL */
Io_mem_connection io_tll(env, TLL_BASE, 0x1000);
addr_t tll_base = (addr_t)env.rm().attach(io_tll.dataspace());
Tll t(tll_base);
/* reset host */
Io_mem_connection io_uhh(env, UHH_BASE, 0x1000);
addr_t uhh_base = (addr_t)env.rm().attach(io_uhh.dataspace());
Uhh uhh(uhh_base);
/* enable hub power */
gpio_power.write(true);
/* reset EHCI */
addr_t ehci_base = uhh_base + 0xc00;
Ehci ehci(ehci_base);
addr_t base[] = { scrm_base, clock_base, tll_base, uhh_base, 0 };
for (int i = 0; base[i]; i++)
env.rm().detach(base[i]);
}
extern "C" void module_ehci_omap_init();
extern "C" int module_usbnet_init();
extern "C" int module_smsc95xx_driver_init();
void platform_hcd_init(Genode::Env &, Services *services)
{
/* register EHCI controller */
module_ehci_omap_init();
/* initialize EHCI */
omap_ehci_init(services->env);
/* setup EHCI-controller platform device */
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
pdev->name = (char *)"ehci-omap";
pdev->id = 0;
pdev->num_resources = 2;
pdev->resource = _ehci;
_ehci_data.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY;
_ehci_data.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED;
_ehci_data.phy_reset = 0;
pdev->dev.platform_data = &_ehci_data;
/*
* Needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c'
*/
static u64 dma_mask = ~(u64)0;
pdev->dev.dma_mask = &dma_mask;
pdev->dev.coherent_dma_mask = ~0;
platform_device_register(pdev);
}

View File

@@ -0,0 +1,23 @@
DDE_LINUX_DIR = $(BASE_DIR)/../dde_linux
include $(DDE_LINUX_DIR)/src/drivers/usb_host/target.inc
TARGET = panda_usb_host_drv
REQUIRES = arm_v7
INC_DIR += $(DDE_LINUX_DIR)/src/drivers/usb_host
INC_DIR += $(DDE_LINUX_DIR)/src/include
INC_DIR += $(DDE_LINUX_DIR)/src/drivers/usb_host/spec/arm
INC_DIR += $(DDE_LINUX_DIR)/src/include/spec/arm
INC_DIR += $(DDE_LINUX_DIR)/src/include/spec/arm_v7
SRC_CC += spec/arm/platform.cc
SRC_CC += spec/panda/platform.cc
SRC_C += usb/host/ehci-omap.c
CC_OPT += -DCONFIG_USB_EHCI_HCD_OMAP=1
CC_OPT += -DCONFIG_USB_EHCI_TT_NEWSCHED=1
CC_OPT += -DCONFIG_EXTCON=1
vpath %.cc $(DDE_LINUX_DIR)/src
vpath % $(DDE_LINUX_DIR)/src/drivers/usb_host

View File

@@ -0,0 +1,78 @@
/*
* \brief Pandaboard specific definitions
* \author Stefan Kalkowski
* \date 2019-05-16
*/
/*
* Copyright (C) 2019 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__INCLUDE__HW__SPEC__ARM__PANDA_BOARD_H_
#define _SRC__INCLUDE__HW__SPEC__ARM__PANDA_BOARD_H_
#include <base/stdint.h>
#include <hw/spec/arm/boot_info.h>
#include <hw/spec/arm/cortex_a9.h>
#include <hw/spec/arm/pl310.h>
#include <hw/uart/tl16c750.h>
namespace Hw::Panda_board {
enum {
/* device IO memory */
MMIO_0_BASE = 0x48000000,
/* normal RAM */
RAM_0_BASE = 0x80000000,
RAM_0_SIZE = 0x40000000,
/* L2 cache */
PL310_MMIO_BASE = 0x48242000,
PL310_MMIO_SIZE = 0x00001000,
/* CPU */
CORTEX_A9_PRIVATE_MEM_BASE = 0x48240000,
CORTEX_A9_PRIVATE_MEM_SIZE = 0x00002000,
CORTEX_A9_PRIVATE_TIMER_CLK = 400000000,
CORTEX_A9_PRIVATE_TIMER_DIV = 200,
CORTEX_A9_WUGEN_MMIO_BASE = 0x48281000,
CORTEX_A9_SCU_MMIO_BASE = 0x48240000,
TL16C750_3_MMIO_BASE = MMIO_0_BASE + 0x20000,
TL16C750_MMIO_SIZE = 0x2000,
TL16C750_CLOCK = 48*1000*1000,
};
using Cpu_mmio = Hw::Cortex_a9_mmio<CORTEX_A9_PRIVATE_MEM_BASE>;
using Serial = Genode::Tl16c750_uart;
enum {
UART_BASE = TL16C750_3_MMIO_BASE,
UART_CLOCK = TL16C750_CLOCK,
};
enum Panda_firmware_opcodes {
CPU_ACTLR_SMP_BIT_RAISE = 0x25,
L2_CACHE_SET_DEBUG_REG = 0x100,
L2_CACHE_ENABLE_REG = 0x102,
L2_CACHE_AUX_REG = 0x109,
};
static inline void call_panda_firmware(Genode::addr_t func,
Genode::addr_t val)
{
register Genode::addr_t _func asm("r12") = func;
register Genode::addr_t _val asm("r0") = val;
asm volatile("dsb \n"
"push {r1-r11} \n"
"smc #0 \n"
"pop {r1-r11} \n"
:: "r" (_func), "r" (_val) : "memory", "cc");
}
}
#endif /* _SRC__INCLUDE__HW__SPEC__ARM__PANDA_BOARD_H_ */

View File

@@ -0,0 +1,246 @@
/*
* \brief UART driver for the Texas instruments TL16C750 module
* \author Martin stein
* \date 2011-10-17
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__DRIVERS__UART__TL16C750_H_
#define _INCLUDE__DRIVERS__UART__TL16C750_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode { class Tl16c750_uart; }
/**
* Base driver Texas instruments TL16C750 UART module
*
* In contrast to the abilities of the TL16C750, this driver targets only
* the basic UART functionalities.
*/
class Genode::Tl16c750_uart : public Mmio
{
protected:
/**
* Least significant divisor part
*/
struct Uart_dll : Register<0x0, 32>
{
struct Clock_lsb : Bitfield<0, 8> { };
};
/**
* Transmit holding register
*/
struct Uart_thr : Register<0x0, 32>
{
struct Thr : Bitfield<0, 8> { };
};
/**
* Receiver holding register
*/
struct Uart_rhr : Register<0x0, 32>
{
struct Rhr : Bitfield<0, 8> { };
};
/**
* Most significant divisor part
*/
struct Uart_dlh : Register<0x4, 32>
{
struct Clock_msb : Bitfield<0, 6> { };
};
/**
* Interrupt enable register
*/
struct Uart_ier : Register<0x4, 32>
{
struct Rhr_it : Bitfield<0, 1> { };
struct Thr_it : Bitfield<1, 1> { };
struct Line_sts_it : Bitfield<2, 1> { };
struct Modem_sts_it : Bitfield<3, 1> { };
struct Sleep_mode : Bitfield<4, 1> { };
struct Xoff_it : Bitfield<5, 1> { };
struct Rts_it : Bitfield<6, 1> { };
struct Cts_it : Bitfield<7, 1> { };
};
/**
* Interrupt identification register
*/
struct Uart_iir : Register<0x8, 32>
{
struct It_pending : Bitfield<0, 1> { };
};
/**
* FIFO control register
*/
struct Uart_fcr : Register<0x8, 32>
{
struct Fifo_enable : Bitfield<0, 1> { };
};
/**
* Line control register
*/
struct Uart_lcr : Register<0xc, 32>
{
struct Char_length : Bitfield<0, 2>
{
enum { _8_BIT = 3 };
};
struct Nb_stop : Bitfield<2, 1>
{
enum { _1_STOP_BIT = 0 };
};
struct Parity_en : Bitfield<3, 1> { };
struct Break_en : Bitfield<6, 1> { };
struct Div_en : Bitfield<7, 1> { };
struct Reg_mode : Bitfield<0, 8>
{
enum { OPERATIONAL = 0, CONFIG_A = 0x80, CONFIG_B = 0xbf };
};
};
/**
* Modem control register
*/
struct Uart_mcr : Register<0x10, 32>
{
struct Tcr_tlr : Bitfield<6, 1> { };
};
/**
* Line status register
*/
struct Uart_lsr : Register<0x14, 32>
{
struct Rx_fifo_empty : Bitfield<0, 1> { };
struct Tx_fifo_empty : Bitfield<5, 1> { };
};
/**
* Mode definition register 1
*/
struct Uart_mdr1 : Register<0x20, 32>
{
struct Mode_select : Bitfield<0, 3>
{
enum { UART_16X = 0, DISABLED = 7 };
};
};
/**
* System control register
*/
struct Uart_sysc : Register<0x54, 32>
{
struct Softreset : Bitfield<1, 1> { };
};
/**
* System status register
*/
struct Uart_syss : Register<0x58, 32>
{
struct Resetdone : Bitfield<0, 1> { };
};
void _init(unsigned long const clock, unsigned long const baud_rate)
{
/* disable UART */
write<Uart_mdr1::Mode_select>(Uart_mdr1::Mode_select::DISABLED);
/* enable access to 'Uart_fcr' and 'Uart_ier' */
write<Uart_lcr::Reg_mode>(Uart_lcr::Reg_mode::OPERATIONAL);
/*
* Configure FIFOs, we don't use any interrupts or DMA,
* thus FIFO trigger and DMA configurations are dispensable.
*/
write<Uart_fcr::Fifo_enable>(1);
/* disable interrupts and sleep mode */
write<Uart_ier>(Uart_ier::Rhr_it::bits(0)
| Uart_ier::Thr_it::bits(0)
| Uart_ier::Line_sts_it::bits(0)
| Uart_ier::Modem_sts_it::bits(0)
| Uart_ier::Sleep_mode::bits(0)
| Uart_ier::Xoff_it::bits(0)
| Uart_ier::Rts_it::bits(0)
| Uart_ier::Cts_it::bits(0));
/* enable access to 'Uart_dlh' and 'Uart_dll' */
write<Uart_lcr::Reg_mode>(Uart_lcr::Reg_mode::CONFIG_B);
/*
* Load the new divisor value (this driver solely uses
* 'UART_16X' mode)
*/
enum { UART_16X_DIVIDER_LOG2 = 4 };
unsigned long const adjusted_br = baud_rate << UART_16X_DIVIDER_LOG2;
double const divisor = (double)clock / adjusted_br;
unsigned long const divisor_uint = (unsigned long)divisor;
write<Uart_dll::Clock_lsb>(divisor_uint);
write<Uart_dlh::Clock_msb>(divisor_uint>>Uart_dll::Clock_lsb::WIDTH);
/*
* Configure protocol formatting and thereby return to
* operational mode.
*/
write<Uart_lcr>(Uart_lcr::Char_length::bits(Uart_lcr::Char_length::_8_BIT)
| Uart_lcr::Nb_stop::bits(Uart_lcr::Nb_stop::_1_STOP_BIT)
| Uart_lcr::Parity_en::bits(0)
| Uart_lcr::Break_en::bits(0)
| Uart_lcr::Div_en::bits(0));
/*
* Switch to UART mode, we don't use hardware or software flow
* control, thus according configurations are dispensable
*/
write<Uart_mdr1::Mode_select>(Uart_mdr1::Mode_select::UART_16X);
}
public:
/**
* Constructor
*
* \param base MMIO base address
* \param clock reference clock
* \param baud_rate targeted baud rate
*/
Tl16c750_uart(addr_t const base, unsigned long const clock,
unsigned long const baud_rate) : Mmio(base)
{
/* reset and init UART */
write<Uart_sysc::Softreset>(1);
while (!read<Uart_syss::Resetdone>()) ;
_init(clock, baud_rate);
}
/**
* Transmit ASCII char 'c'
*/
void put_char(char const c)
{
/* wait as long as the transmission buffer is full */
while (!read<Uart_lsr::Tx_fifo_empty>()) ;
/* transmit character */
write<Uart_thr::Thr>(c);
}
};
#endif /* _INCLUDE__DRIVERS__UART__TL16C750_H_ */

24
tool/run/boot_dir/hw Normal file
View File

@@ -0,0 +1,24 @@
source [genode_dir]/tool/run/boot_dir/hw
proc bootstrap_link_address { } {
if {[have_spec "panda"]} { return "0x88000000" }
puts "unknown platform no linker address known"
exit -1
}
##
# Base source archive within depot
#
proc base_src { } {
if {[have_spec panda]} { return base-hw-panda }
global specs
puts stderr "Test requires base-hw kernel archive, which is missing for this build configuration"
puts stderr " SPECS=\"$specs\""
exit 0
}