committed by
Norman Feske
parent
0ed545e55a
commit
0489c3edf4
17
lib/mk/spec/arm_v7/bootstrap-hw-panda.mk
Normal file
17
lib/mk/spec/arm_v7/bootstrap-hw-panda.mk
Normal 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
|
||||
20
lib/mk/spec/arm_v7/core-hw-panda.mk
Normal file
20
lib/mk/spec/arm_v7/core-hw-panda.mk
Normal 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
11
mk/spec/panda.mk
Normal 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
|
||||
41
recipes/src/base-hw-panda/content.mk
Normal file
41
recipes/src/base-hw-panda/content.mk
Normal 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
|
||||
1
recipes/src/base-hw-panda/hash
Normal file
1
recipes/src/base-hw-panda/hash
Normal file
@@ -0,0 +1 @@
|
||||
2020-03-23-b 841ce3bb426e5685d1c08612acdd78b70eb5e7b8
|
||||
2
recipes/src/base-hw-panda/used_apis
Normal file
2
recipes/src/base-hw-panda/used_apis
Normal file
@@ -0,0 +1,2 @@
|
||||
base-hw
|
||||
base
|
||||
81
src/bootstrap/spec/panda/board.h
Normal file
81
src/bootstrap/spec/panda/board.h
Normal 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_ */
|
||||
50
src/bootstrap/spec/panda/platform.cc
Normal file
50
src/bootstrap/spec/panda/platform.cc
Normal 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");
|
||||
}
|
||||
54
src/core/spec/panda/board.h
Normal file
54
src/core/spec/panda/board.h
Normal 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_ */
|
||||
129
src/drivers/framebuffer/spec/omap4/dispc.h
Normal file
129
src/drivers/framebuffer/spec/omap4/dispc.h
Normal 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_ */
|
||||
293
src/drivers/framebuffer/spec/omap4/driver.h
Normal file
293
src/drivers/framebuffer/spec/omap4/driver.h
Normal 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;
|
||||
}
|
||||
29
src/drivers/framebuffer/spec/omap4/dss.h
Normal file
29
src/drivers/framebuffer/spec/omap4/dss.h
Normal 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_ */
|
||||
197
src/drivers/framebuffer/spec/omap4/hdmi.h
Normal file
197
src/drivers/framebuffer/spec/omap4/hdmi.h
Normal 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_ */
|
||||
207
src/drivers/framebuffer/spec/omap4/main.cc
Normal file
207
src/drivers/framebuffer/spec/omap4/main.cc
Normal 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); }
|
||||
15
src/drivers/framebuffer/spec/omap4/target.mk
Normal file
15
src/drivers/framebuffer/spec/omap4/target.mk
Normal 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 =
|
||||
272
src/drivers/gpio/spec/omap4/driver.h
Normal file
272
src/drivers/gpio/spec/omap4/driver.h
Normal 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_ */
|
||||
50
src/drivers/gpio/spec/omap4/gpio.h
Normal file
50
src/drivers/gpio/spec/omap4/gpio.h
Normal 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_ */
|
||||
64
src/drivers/gpio/spec/omap4/main.cc
Normal file
64
src/drivers/gpio/spec/omap4/main.cc
Normal 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); }
|
||||
8
src/drivers/gpio/spec/omap4/target.mk
Normal file
8
src/drivers/gpio/spec/omap4/target.mk
Normal 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)
|
||||
|
||||
458
src/drivers/sd_card/spec/omap4/driver.cc
Normal file
458
src/drivers/sd_card/spec/omap4/driver.cc
Normal 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++);
|
||||
}
|
||||
}
|
||||
223
src/drivers/sd_card/spec/omap4/driver.h
Normal file
223
src/drivers/sd_card/spec/omap4/driver.h
Normal 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_ */
|
||||
9
src/drivers/sd_card/spec/omap4/target.mk
Normal file
9
src/drivers/sd_card/spec/omap4/target.mk
Normal 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)
|
||||
301
src/drivers/usb_host/spec/panda/platform.cc
Normal file
301
src/drivers/usb_host/spec/panda/platform.cc
Normal 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);
|
||||
}
|
||||
23
src/drivers/usb_host/spec/panda/target.mk
Normal file
23
src/drivers/usb_host/spec/panda/target.mk
Normal 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
|
||||
78
src/include/hw/spec/arm/panda_board.h
Normal file
78
src/include/hw/spec/arm/panda_board.h
Normal 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_ */
|
||||
246
src/include/hw/uart/tl16c750.h
Normal file
246
src/include/hw/uart/tl16c750.h
Normal 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
24
tool/run/boot_dir/hw
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user