os: use async IRQ and server lib in drivers

Use the new asynchronous IRQ interface in the mostly used drivers, e.g.:

* ahci_drv: x86/exynos5
* gpio_drv: imx53/omap4
* input_drv: imx53/dummy
* ps2_drv: x86/pl050
* timer_drv

Now, the Irq_session is requested from Gpio::Session:

From now on we use an asynchronous IRQ interface. To prevent triggering
another GPIO IRQ while currently handling the former one, IRQs must
now by acknowledged explicitly. While here, we also changed the GPIO
session interface regarding IRQ management. The generic GPIO component
now wraps the Irq_session managed by the backend instead of using the
GPIO backend methods directly. A client using the GPIO session may
request the Irq_session_capability by calling
'Gpio::Session::irq_session()' and can use this capability when using
a local Irq_session_client.

Issue #1456.
devel
Josef Söntgen 8 years ago committed by Christian Helmuth
parent bfb47cfd4e
commit 85599c072f

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -30,39 +30,62 @@ class Gpio::Session_component : public Genode::Rpc_object<Gpio::Session>
{
private:
Driver &_driver;
unsigned long _pin;
Genode::Signal_context_capability _sigh;
struct Irq_session_component : public Genode::Rpc_object<Genode::Irq_session>
{
Driver &_driver;
unsigned long _pin;
Irq_session_component(Driver &driver, unsigned long pin)
: _driver(driver), _pin(pin) { }
/***************************
** Irq_session interface **
***************************/
void ack_irq() override { _driver.ack_irq(_pin); }
void sigh(Genode::Signal_context_capability sigh) override {
_driver.register_signal(_pin, sigh); }
};
Genode::Rpc_entrypoint &_ep;
Driver &_driver;
unsigned long _pin;
Irq_session_component _irq_component;
Genode::Irq_session_capability _irq_cap;
public:
Session_component(Driver &driver, unsigned long gpio_pin)
: _driver(driver), _pin(gpio_pin) { }
Session_component(Genode::Rpc_entrypoint &ep,
Driver &driver,
unsigned long gpio_pin)
: _ep(ep), _driver(driver), _pin(gpio_pin),
_irq_component(_driver, _pin),
_irq_cap(_ep.manage(&_irq_component)) { }
~Session_component() { _ep.dissolve(&_irq_component); }
~Session_component()
{
if (_sigh.valid())
_driver.unregister_signal(_pin);
}
/************************************
/*****************************
** Gpio::Session interface **
************************************/
*****************************/
void direction(Direction d) { _driver.direction(_pin, (d == IN)); }
void write(bool level) { _driver.write(_pin, level); }
bool read() { return _driver.read(_pin); }
void irq_enable(bool enable) { _driver.irq_enable(_pin, enable); }
void irq_sigh(Genode::Signal_context_capability cap)
void debouncing(unsigned int us)
{
if (cap.valid()) {
_sigh = cap;
_driver.register_signal(_pin, cap);
}
if (us) {
_driver.debounce_time(_pin, us);
_driver.debounce_enable(_pin, true);
} else
_driver.debounce_enable(_pin, false);
}
void irq_type(Irq_type type)
Genode::Irq_session_capability irq_session(Irq_type type)
{
switch (type) {
case HIGH_LEVEL:
@ -77,15 +100,10 @@ class Gpio::Session_component : public Genode::Rpc_object<Gpio::Session>
case FALLING_EDGE:
_driver.falling_detect(_pin);
};
}
void debouncing(unsigned int us)
{
if (us) {
_driver.debounce_time(_pin, us);
_driver.debounce_enable(_pin, true);
} else
_driver.debounce_enable(_pin, false);
_driver.irq_enable(_pin, true);
return _irq_cap;
}
};
@ -94,7 +112,8 @@ class Gpio::Root : public Genode::Root_component<Gpio::Session_component>
{
private:
Driver &_driver;
Genode::Rpc_entrypoint &_ep;
Driver &_driver;
protected:
@ -114,7 +133,7 @@ class Gpio::Root : public Genode::Root_component<Gpio::Session_component>
throw Genode::Root::Quota_exceeded();
}
return new (md_alloc()) Session_component(_driver, pin);
return new (md_alloc()) Session_component(_ep, _driver, pin);
}
public:
@ -122,7 +141,7 @@ class Gpio::Root : public Genode::Root_component<Gpio::Session_component>
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc, Driver &driver)
: Genode::Root_component<Gpio::Session_component>(session_ep, md_alloc),
_driver(driver) { }
_ep(*session_ep), _driver(driver) { }
};

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -92,6 +92,13 @@ struct Gpio::Driver
*/
virtual void irq_enable(unsigned gpio, bool enable) = 0;
/**
* Acknowledge IRQ for specified GPIO pin
*
* \param gpio corresponding gpio pin number
*/
virtual void ack_irq(unsigned gpio) = 0;
/**
* Register signal handler for interrupts
*

@ -7,7 +7,7 @@
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -27,15 +27,13 @@ struct Gpio::Session_client : Genode::Rpc_client<Session>
explicit Session_client(Session_capability session)
: Genode::Rpc_client<Session>(session) { }
void direction(Direction d) override { call<Rpc_direction>(d); }
void write(bool level) override { call<Rpc_write>(level); }
bool read() override { return call<Rpc_read>(); }
void debouncing(unsigned int us) override { call<Rpc_debouncing>(us); }
void irq_type(Irq_type it) override { call<Rpc_irq_type>(it); }
void irq_enable(bool enable) override { call<Rpc_irq_enable>(enable); }
void direction(Direction d) override { call<Rpc_direction>(d); }
void write(bool level) override { call<Rpc_write>(level); }
bool read() override { return call<Rpc_read>(); }
void debouncing(unsigned int us) override { call<Rpc_debouncing>(us); }
void irq_sigh(Genode::Signal_context_capability cap) override {
call<Rpc_irq_sigh>(cap); }
Genode::Irq_session_capability irq_session(Irq_type type) override {
return call<Rpc_irq_session>(type); }
};
#endif /* _INCLUDE__GPIO_SESSION_H__CLIENT_H_ */

@ -7,7 +7,7 @@
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -19,6 +19,7 @@
#include <base/signal.h>
#include <dataspace/capability.h>
#include <session/session.h>
#include <irq_session/capability.h>
namespace Gpio { struct Session; }
@ -62,42 +63,26 @@ struct Gpio::Session : Genode::Session
virtual void debouncing(unsigned int us) = 0;
/**
* Configure the type of interrupt for the GPIO pin
* Rquest IRQ session
*
* \param it type of IRQ
* \param type type of IRQ
*/
virtual void irq_type(Irq_type it) = 0;
/**
* Enable or disable the interrupt of the GPIO pin
*
* \param enable interrupt status( true - enable, false - disable)
*/
virtual void irq_enable(bool enable) = 0;
/**
* Register signal handler to be notified on interrupt
*
* \param cap capability of signal-context to handle GPIO interrupt
*/
virtual void irq_sigh(Genode::Signal_context_capability cap) = 0;
virtual Genode::Irq_session_capability irq_session(Irq_type type) = 0;
/*******************
** RPC interface **
*******************/
GENODE_RPC(Rpc_direction, void, direction, Direction);
GENODE_RPC(Rpc_write, void, write, bool);
GENODE_RPC(Rpc_read, bool, read);
GENODE_RPC(Rpc_debouncing, void, debouncing, unsigned int);
GENODE_RPC(Rpc_irq_type, void, irq_type, Irq_type);
GENODE_RPC(Rpc_irq_enable, void, irq_enable, bool);
GENODE_RPC(Rpc_irq_sigh, void, irq_sigh, Genode::Signal_context_capability);
GENODE_RPC(Rpc_direction, void, direction, Direction);
GENODE_RPC(Rpc_write, void, write, bool);
GENODE_RPC(Rpc_read, bool, read);
GENODE_RPC(Rpc_debouncing, void, debouncing, unsigned int);
GENODE_RPC(Rpc_irq_session, Genode::Irq_session_capability,
irq_session, Irq_type);
GENODE_RPC_INTERFACE(Rpc_direction, Rpc_write, Rpc_read,
Rpc_debouncing, Rpc_irq_type, Rpc_irq_enable,
Rpc_irq_sigh);
Rpc_debouncing, Rpc_irq_session);
};
#endif /* _INCLUDE__GPIO_SESSION__GPIO_SESSION_H_ */

@ -1,5 +1,5 @@
SRC_CC += main.cc
LIBS += base alarm
LIBS += base alarm server
INC_DIR += $(REP_DIR)/src/drivers/timer/include
vpath main.cc $(REP_DIR)/src/drivers/timer

@ -902,6 +902,8 @@ struct Sata_ahci : Attached_mmio
/* port 0 settings */
unsigned p0_speed;
Irq_connection p0_irq;
Genode::Signal_receiver p0_irq_rec;
Genode::Signal_context p0_irq_ctx;
enum { SATA_3_MAX_SPEED = 3 };
@ -922,7 +924,10 @@ struct Sata_ahci : Attached_mmio
dbc_stable_trials(5),
p0_speed(SATA_3_MAX_SPEED),
p0_irq(Genode::Board_base::SATA_IRQ)
{ }
{
p0_irq.sigh(p0_irq_rec.manage(&p0_irq_ctx));
p0_irq.ack_irq();
}
/**
* Clear all interrupts at port 0
@ -1145,7 +1150,7 @@ struct Sata_ahci : Attached_mmio
{
typedef typename P0IS_BIT::Bitfield_base P0is_bit;
write<P0ci>(1 << tag);
p0_irq.wait_for_irq();
p0_irq_rec.wait_for_signal();
if (!read<Is::Ips>()) {
PERR("ATA0 no IRQ raised");
return -1;
@ -1269,6 +1274,7 @@ struct Sata_ahci : Attached_mmio
printf("ATA0 supports UDMA-133 and NCQ with queue depth %u\n",
dev_id->queue_depth + 1);
write<Is::Ips>(1);
p0_irq.ack_irq();
/* destroy receive buffer DMA */
env()->rm_session()->detach(dev_id_virt);
@ -1300,6 +1306,7 @@ struct Sata_ahci : Attached_mmio
/* end command */
write<Is::Ips>(1);
p0_irq.ack_irq();
/* check for hidden blocks */
return max_native_addr + 1 != block_cnt;
@ -1344,6 +1351,7 @@ struct Sata_ahci : Attached_mmio
}
/* end command */
write<Is::Ips>(1);
p0_irq.ack_irq();
return 0;
}
@ -1668,7 +1676,7 @@ struct Sata_ahci : Attached_mmio
/* issue command and wait for completion */
write<P0sact>(1 << tag);
write<P0ci>(1 << tag);
p0_irq.wait_for_irq();
p0_irq_rec.wait_for_signal();
/* get port back ready and deteremine command state */
int ret = p0_handle_irqs(lba);
@ -1684,6 +1692,7 @@ struct Sata_ahci : Attached_mmio
return -1;
}
write<Is::Ips>(1);
p0_irq.ack_irq();
}
return ret;
}

@ -370,6 +370,8 @@ class Ahci_device_base
Generic_ctrl *_ctrl; /* generic host control */
Ahci_port *_port; /* port base of device */
Irq_connection *_irq; /* device IRQ */
Genode::Signal_receiver _irq_rec; /* IRQ signal receiver */
Genode::Signal_context _irq_ctx; /* IRQ signal context */
size_t _block_cnt; /* number of blocks on device */
Command_list *_cmd_list; /* pointer to command list */
Command_table *_cmd_table; /* pointer to command table */
@ -453,7 +455,7 @@ class Ahci_device_base
while (!status) {
/* wait for interrupt */
_irq->wait_for_irq();
_irq_rec.wait_for_signal();
if (verbose)
PDBG("Int status (IRQ): global: %x port: %x error: %x",
@ -479,6 +481,8 @@ class Ahci_device_base
/* acknowledge global port interrupt */
_ctrl->hba_interrupt_ack();
_irq->ack_irq();
/* disable hba */
_port->hba_disable();
}

@ -184,6 +184,10 @@ class Ahci_device : public Ahci_device_base
_disable_msi(pci_device);
device->_irq = new(env()->heap()) Irq_connection(intr & 0xff);
Genode::Signal_context_capability cap = device->_irq_rec.manage(&device->_irq_ctx);
device->_irq->sigh(cap);
device->_irq->ack_irq();
/* remember pci_device to be able to allocate ram memory which is dma able */
device->_pci_device_cap = device_cap;
device->_pci_device = pci_device;

@ -113,7 +113,19 @@ class I2c_interface : public Attached_mmio
TX_DELAY_US = 1,
};
Irq_connection _irq;
Irq_connection _irq;
Genode::Signal_receiver _irq_rec;
Genode::Signal_context _irq_ctx;
/**
* Wait until the IRQ signal was received
*/
void _wait_for_irq()
{
_irq_rec.wait_for_signal();
_irq.ack_irq();
}
/**
* Stop a running transfer as master
@ -166,7 +178,7 @@ class I2c_interface : public Attached_mmio
write<Con>(con);
Stat::Busy::set(stat, 1);
write<Stat>(stat);
_irq.wait_for_irq();
_wait_for_irq();
if (_arbitration_error()) return -1;
return 0;
}
@ -196,6 +208,7 @@ class I2c_interface : public Attached_mmio
return 0;
}
public:
/**
@ -224,8 +237,13 @@ class I2c_interface : public Attached_mmio
Lc::Sda_out_delay::set(lc, 2);
Lc::Filter_en::set(lc, 1);
write<Lc>(lc);
_irq.sigh(_irq_rec.manage(&_irq_ctx));
_irq.ack_irq();
}
~I2c_interface() { _irq_rec.dissolve(&_irq_ctx); }
/**
* Transmit an I2C message as master
*
@ -252,7 +270,7 @@ class I2c_interface : public Attached_mmio
/* finish last byte and prepare for next one */
off++;
write<Con::Irq_pending>(0);
_irq.wait_for_irq();
_wait_for_irq();
if (_arbitration_error()) return -1;
}
/* end message transfer */
@ -285,7 +303,7 @@ class I2c_interface : public Attached_mmio
while (1)
{
/* receive next message byte */
_irq.wait_for_irq();
_wait_for_irq();
if (_arbitration_error()) return -1;
buf[off] = read<Ds>();
off++;
@ -619,14 +637,6 @@ class I2c_hdmi : public I2c_interface
}
};
/**
* Return singleton of device instance
*/
static I2c_hdmi * i2c_hdmi()
{
static I2c_hdmi s;
return &s;
}
/**
* Converts input stream from video mixer into HDMI packet stream for HDMI PHY
@ -942,12 +952,15 @@ class Hdmi : public Attached_mmio
write<Fp_3d::Value>(0);
}
I2c_hdmi _i2c_hdmi;
public:
/**
* Constructor
*/
Hdmi() : Attached_mmio(0x14530000, 0xa0000) { }
Hdmi()
: Attached_mmio(0x14530000, 0xa0000), _i2c_hdmi() { }
/**
* Initialize HDMI controller for video output only
@ -978,12 +991,12 @@ class Hdmi : public Attached_mmio
}
/* set-up HDMI PHY */
write<Phy_con_0::Pwr_off>(0);
if (i2c_hdmi()->stop_hdmi_phy()) return -1;
if (_i2c_hdmi.stop_hdmi_phy()) return -1;
write<Phy_rstout::Reset>(1);
delayer()->usleep(10000);
write<Phy_rstout::Reset>(0);
delayer()->usleep(10000);
if (i2c_hdmi()->setup_and_start_hdmi_phy(pixel_clk)) return -1;
if (_i2c_hdmi.setup_and_start_hdmi_phy(pixel_clk)) return -1;
/* reset HDMI CORE */
write<Core_rstout::Reset>(0);
@ -1095,15 +1108,6 @@ class Hdmi : public Attached_mmio
}
};
/**
* Return singleton of device instance
*/
static Hdmi * hdmi()
{
static Hdmi s;
return &s;
}
/*************************
** Framebuffer::Driver **
@ -1140,7 +1144,8 @@ int Framebuffer::Driver::_init_hdmi(addr_t fb_phys)
if (err) { return -1; }
/* set-up HDMI to feed connected device */
err = hdmi()->init_hdmi(_fb_width, _fb_height);
static Hdmi hdmi;
err = hdmi.init_hdmi(_fb_width, _fb_height);
if (err) { return -1; }
return 0;
}

@ -17,6 +17,7 @@
/* Genode includes */
#include <base/stdint.h>
#include <base/printf.h>
#include <os/server.h>
namespace Framebuffer
{

@ -11,9 +11,6 @@
* under the terms of the GNU General Public License version 2.
*/
/* local includes */
#include <driver.h>
/* Genode includes */
#include <framebuffer_session/framebuffer_session.h>
#include <cap_session/connection.h>
@ -22,6 +19,10 @@
#include <base/sleep.h>
#include <os/config.h>
#include <os/static_root.h>
#include <os/server.h>
/* local includes */
#include <driver.h>
namespace Framebuffer
{
@ -111,47 +112,52 @@ class Framebuffer::Session_component
};
/**
* Program entrypoint
*/
int main(int, char **)
struct Main
{
using namespace Framebuffer;
/* default config */
size_t width = 1920;
size_t height = 1080;
Driver::Output output = Driver::OUTPUT_HDMI;
/* try to read custom user config */
try {
char out[5] = { };
Genode::Xml_node config_node = Genode::config()->xml_node();
config_node.attribute("width").value(&width);
config_node.attribute("height").value(&height);
config_node.attribute("output").value(out, sizeof(out));
if (!Genode::strcmp(out, "LCD")) {
output = Driver::OUTPUT_LCD;
Server::Entrypoint &ep;
Framebuffer::Driver driver;
Main(Server::Entrypoint &ep)
: ep(ep), driver()
{
using namespace Framebuffer;
/* default config */
size_t width = 1920;
size_t height = 1080;
Driver::Output output = Driver::OUTPUT_HDMI;
/* try to read custom user config */
try {
char out[5] = { 0 };
Genode::Xml_node config_node = Genode::config()->xml_node();
config_node.attribute("width").value(&width);
config_node.attribute("height").value(&height);
config_node.attribute("output").value(out, sizeof(out));
if (!Genode::strcmp(out, "LCD")) {
output = Driver::OUTPUT_LCD;
}
}
catch (...) {
PDBG("using default configuration: HDMI@%dx%d", width, height);
}
/* let entrypoint serve the framebuffer session and root interfaces */
static Session_component fb_session(driver, width, height, output);
static Static_root<Framebuffer::Session> fb_root(ep.manage(fb_session));
/* announce service and relax */
env()->parent()->announce(ep.manage(fb_root));
}
catch (...) {
PDBG("using default configuration: HDMI@%dx%d", width, height);
}
/* create server backend */
static Driver driver;
/* create server entrypoint */
enum { STACK_SIZE = 4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep");
/* let entrypoint serve the framebuffer session and root interfaces */
static Session_component fb_session(driver, width, height, output);
static Static_root<Framebuffer::Session> fb_root(ep.manage(&fb_session));
/* announce service and relax */
env()->parent()->announce(ep.manage(&fb_root));
sleep_forever();
return 0;
}
};
/************
** Server **
************/
namespace Server {
char const *name() { return "fb_drv_ep"; }
size_t stack_size() { return 1024*sizeof(long); }
void construct(Entrypoint &ep) { static Main server(ep); }
}

@ -1,5 +1,5 @@
TARGET = fb_drv
REQUIRES = exynos5
SRC_CC += main.cc driver.cc
LIBS += base config
LIBS += base config server
INC_DIR += $(PRG_DIR)

@ -22,6 +22,7 @@
#include <gpio/driver.h>
#include <irq_session/connection.h>
#include <timer_session/connection.h>
#include <os/server.h>
/* local includes */
#include "gpio.h"
@ -34,6 +35,7 @@ class Imx53_driver : public Gpio::Driver
private:
enum {
PIN_SHIFT = 5,
MAX_BANKS = 7,
MAX_PINS = 32
};
@ -52,31 +54,44 @@ class Imx53_driver : public Gpio::Driver
{
public:
void handle_irq();
void handle_irq()
{
unsigned long status = _reg.read<Gpio_reg::Int_stat>();
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();
}
}
private:
class Irq_handler : public Genode::Thread<4096>
class Irq_handler
{
private:
Genode::Irq_connection _irq;
Gpio_bank *_bank;
Genode::Irq_connection _irq;
Genode::Signal_rpc_member<Irq_handler> _dispatcher;
Gpio_bank *_bank;
void _handle(unsigned)
{
_bank->handle_irq();
_irq.ack_irq();
}
public:
Irq_handler(unsigned irq, Gpio_bank *bank)
: Genode::Thread<4096>("irq handler"),
_irq(irq), _bank(bank) { start(); }
public:
void entry()
Irq_handler(Server::Entrypoint &ep,
unsigned irq, Gpio_bank *bank)
: _irq(irq), _dispatcher(ep, *this, &Irq_handler::_handle),
_bank(bank)
{
while (true) {
_irq.wait_for_irq();
_bank->handle_irq();
}
_irq.sigh(_dispatcher);
_irq.ack_irq();
}
};
Gpio_reg _reg;
@ -84,15 +99,14 @@ class Imx53_driver : public Gpio::Driver
Irq_handler _irqh_high;
Genode::Signal_context_capability _sig_cap[MAX_PINS];
bool _irq_enabled[MAX_PINS];
Genode::Lock _lock;
public:
Gpio_bank(Genode::addr_t base, Genode::size_t size,
unsigned irq_low, unsigned irq_high)
Gpio_bank(Server::Entrypoint &ep, Genode::addr_t base,
Genode::size_t size, unsigned irq_low, unsigned irq_high)
: _reg(base, size),
_irqh_low(irq_low, this),
_irqh_high(irq_high, this) { }
_irqh_low(ep, irq_low, this),
_irqh_high(ep, irq_high, this) { }
Gpio_reg* regs() { return &_reg; }
@ -102,20 +116,70 @@ class Imx53_driver : public Gpio::Driver
_irq_enabled[pin] = enable;
}
void ack_irq(int pin)
{
_reg.write<Gpio_reg::Int_stat>(1, pin);
}
void sigh(int pin, Genode::Signal_context_capability cap) {
_sig_cap[pin] = cap; }
};
Server::Entrypoint &_ep;
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_6;
static Gpio_bank _gpio_bank[MAX_BANKS];
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;
case 6:
return &_gpio_bank_6;
}
PERR("no Gpio_bank for pin %d available", gpio);
return 0;
}
int _gpio_bank_index(int gpio) { return gpio >> 5; }
int _gpio_index(int gpio) { return gpio & 0x1f; }
Imx53_driver()
Imx53_driver(Server::Entrypoint &ep)
:
_ep(ep),
_gpio_bank_0(_ep, Genode::Board_base::GPIO1_MMIO_BASE, Genode::Board_base::GPIO1_MMIO_SIZE,
Genode::Board_base::GPIO1_IRQL, Genode::Board_base::GPIO1_IRQH),
_gpio_bank_1(_ep, Genode::Board_base::GPIO2_MMIO_BASE, Genode::Board_base::GPIO2_MMIO_SIZE,
Genode::Board_base::GPIO2_IRQL, Genode::Board_base::GPIO2_IRQH),
_gpio_bank_2(_ep, Genode::Board_base::GPIO3_MMIO_BASE, Genode::Board_base::GPIO3_MMIO_SIZE,
Genode::Board_base::GPIO3_IRQL, Genode::Board_base::GPIO3_IRQH),
_gpio_bank_3(_ep, Genode::Board_base::GPIO4_MMIO_BASE, Genode::Board_base::GPIO4_MMIO_SIZE,
Genode::Board_base::GPIO4_IRQL, Genode::Board_base::GPIO4_IRQH),
_gpio_bank_4(_ep, Genode::Board_base::GPIO5_MMIO_BASE, Genode::Board_base::GPIO5_MMIO_SIZE,
Genode::Board_base::GPIO5_IRQL, Genode::Board_base::GPIO5_IRQH),
_gpio_bank_5(_ep, Genode::Board_base::GPIO6_MMIO_BASE, Genode::Board_base::GPIO6_MMIO_SIZE,
Genode::Board_base::GPIO6_IRQL, Genode::Board_base::GPIO6_IRQH),
_gpio_bank_6(_ep, Genode::Board_base::GPIO7_MMIO_BASE, Genode::Board_base::GPIO7_MMIO_SIZE,
Genode::Board_base::GPIO7_IRQL, Genode::Board_base::GPIO7_IRQH)
{
for (unsigned i = 0; i < MAX_BANKS; ++i) {
Gpio_reg *regs = _gpio_bank[i].regs();
Gpio_reg *regs = _gpio_bank(i << PIN_SHIFT)->regs();
for (unsigned j = 0; j < MAX_PINS; j++) {
regs->write<Gpio_reg::Int_conf>(Gpio_reg::Int_conf::LOW_LEVEL, j);
regs->write<Gpio_reg::Int_mask>(0, j);
@ -124,10 +188,10 @@ class Imx53_driver : public Gpio::Driver
}
}
public:
static Imx53_driver& factory();
public:
static Imx53_driver &factory(Server::Entrypoint &ep);
/******************************
** Gpio::Driver interface **
@ -137,7 +201,7 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d input=%d", gpio, input);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Dir>(input ? 0 : 1,
_gpio_index(gpio));
}
@ -146,7 +210,7 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d level=%d", gpio, level);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Data>(level ? 1 : 0,
_gpio_index(gpio));
@ -156,7 +220,7 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d", gpio);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
return gpio_reg->read<Gpio_reg::Pad_stat>(_gpio_index(gpio));
}
@ -174,7 +238,7 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d", gpio);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Int_conf>(Gpio_reg::Int_conf::FAL_EDGE,
_gpio_index(gpio));
}
@ -183,7 +247,7 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d", gpio);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Int_conf>(Gpio_reg::Int_conf::RIS_EDGE,
_gpio_index(gpio));
}
@ -192,7 +256,7 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d", gpio);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Int_conf>(Gpio_reg::Int_conf::HIGH_LEVEL,
_gpio_index(gpio));
}
@ -201,7 +265,7 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d", gpio);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Int_conf>(Gpio_reg::Int_conf::LOW_LEVEL,
_gpio_index(gpio));
}
@ -210,7 +274,14 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d enable=%d", gpio, enable);
_gpio_bank[_gpio_bank_index(gpio)].irq(_gpio_index(gpio), enable);
_gpio_bank(gpio)->irq(_gpio_index(gpio), enable);
}
void ack_irq(unsigned gpio)
{
if (verbose) PDBG("gpio=%d ack_irq", gpio);
_gpio_bank(gpio)->ack_irq(_gpio_index(gpio));
}
void register_signal(unsigned gpio,
@ -218,59 +289,24 @@ class Imx53_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d", gpio);
_gpio_bank[_gpio_bank_index(gpio)].sigh(_gpio_index(gpio), cap); }
_gpio_bank(gpio)->sigh(_gpio_index(gpio), cap); }
void unregister_signal(unsigned gpio)
{
if (verbose) PDBG("gpio=%d", gpio);
Genode::Signal_context_capability cap;
_gpio_bank[_gpio_bank_index(gpio)].sigh(_gpio_index(gpio), cap);
_gpio_bank(gpio)->sigh(_gpio_index(gpio), cap);
}
bool gpio_valid(unsigned gpio) { return gpio < (MAX_PINS*MAX_BANKS); }
};
Imx53_driver::Gpio_bank Imx53_driver::_gpio_bank[Imx53_driver::MAX_BANKS] = {
{ Genode::Board_base::GPIO1_MMIO_BASE, Genode::Board_base::GPIO1_MMIO_SIZE,
Genode::Board_base::GPIO1_IRQL, Genode::Board_base::GPIO1_IRQH },
{ Genode::Board_base::GPIO2_MMIO_BASE, Genode::Board_base::GPIO2_MMIO_SIZE,
Genode::Board_base::GPIO2_IRQL, Genode::Board_base::GPIO2_IRQH },
{ Genode::Board_base::GPIO3_MMIO_BASE, Genode::Board_base::GPIO3_MMIO_SIZE,
Genode::Board_base::GPIO3_IRQL, Genode::Board_base::GPIO3_IRQH },
{ Genode::Board_base::GPIO4_MMIO_BASE, Genode::Board_base::GPIO4_MMIO_SIZE,
Genode::Board_base::GPIO4_IRQL, Genode::Board_base::GPIO4_IRQH },
{ Genode::Board_base::GPIO5_MMIO_BASE, Genode::Board_base::GPIO5_MMIO_SIZE,
Genode::Board_base::GPIO5_IRQL, Genode::Board_base::GPIO5_IRQH },
{ Genode::Board_base::GPIO6_MMIO_BASE, Genode::Board_base::GPIO6_MMIO_SIZE,
Genode::Board_base::GPIO6_IRQL, Genode::Board_base::GPIO6_IRQH },
{ Genode::Board_base::GPIO7_MMIO_BASE, Genode::Board_base::GPIO7_MMIO_SIZE,
Genode::Board_base::GPIO7_IRQL, Genode::Board_base::GPIO7_IRQH }
};
Imx53_driver& Imx53_driver::factory()
Imx53_driver &Imx53_driver::factory(Server::Entrypoint &ep)
{
static Imx53_driver driver;
static Imx53_driver driver(ep);
return driver;
}
void Imx53_driver::Gpio_bank::handle_irq()
{
Genode::Lock::Guard lock_guard(_lock);
unsigned long status = _reg.read<Gpio_reg::Int_stat>();
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();
}
_reg.write<Gpio_reg::Int_stat>(0xffffffff);
}
#endif /* _DRIVER_H_ */

@ -8,7 +8,7 @@
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -20,35 +20,46 @@
#include <cap_session/connection.h>
#include <gpio/component.h>
#include <gpio/config.h>
#include <os/server.h>
/* local includes */
#include <driver.h>
int main(int, char **)
struct Main
{
using namespace Genode;
Server::Entrypoint &ep;
Genode::Sliced_heap sliced_heap;
Imx53_driver &driver;
Gpio::Root root;
printf("--- i.MX53 gpio driver ---\n");
Main(Server::Entrypoint &ep)
:
ep(ep),
sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()),
driver(Imx53_driver::factory(ep)),
root(&ep.rpc_ep(), &sliced_heap, driver)
{
using namespace Genode;
Imx53_driver &driver = Imx53_driver::factory();
Gpio::process_config(driver);
printf("--- i.MX53 gpio driver ---\n");
/*
* Initialize server entry point
*/
enum { STACK_SIZE = 4096 };
static Cap_connection cap;
Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
static Rpc_entrypoint ep(&cap, STACK_SIZE, "gpio_ep");
static Gpio::Root gpio_root(&ep, &sliced_heap, driver);
Gpio::process_config(driver);
/*
* Announce service
*/
env()->parent()->announce(ep.manage(&gpio_root));
/*
* Announce service
*/
env()->parent()->announce(ep.manage(root));
}
};
Genode::sleep_forever();
return 0;
}
/************
** Server **
************/
namespace Server {
char const *name() { return "gpio_drv_ep"; }
size_t stack_size() { return 1024*sizeof(long); }
void construct(Entrypoint &ep) { static Main server(ep); }
}

@ -1,7 +1,7 @@
TARGET = gpio_drv
REQUIRES = imx53
SRC_CC = main.cc
LIBS = base config
LIBS = base config server
INC_DIR += $(PRG_DIR)
vpath main.cc $(PRG_DIR)

@ -33,6 +33,7 @@ class Omap4_driver : public Gpio::Driver
private:
enum {
PIN_SHIFT = 5,
MAX_BANKS = 6,
MAX_PINS = 32
};
@ -47,44 +48,45 @@ class Omap4_driver : public Gpio::Driver
} _delayer;
class Gpio_bank : public Genode::Thread<4096>
class Gpio_bank
{
private:
Gpio_reg _reg;
Genode::Irq_connection _irq;
Genode::Signal_context_capability _sig_cap[MAX_PINS];
bool _irq_enabled[MAX_PINS];
Gpio_reg _reg;
Genode::Irq_connection _irq;
Genode::Signal_rpc_member<Gpio_bank> _dispatcher;
Genode::Signal_context_capability _sig_cap[MAX_PINS];
bool _irq_enabled[MAX_PINS];
void _handle(unsigned)
{
_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::addr_t base, Genode::size_t size,
Gpio_bank(Server::Entrypoint &ep,
Genode::addr_t base, Genode::size_t size,
unsigned irq)
: Genode::Thread<4096>("irq handler"),
_reg(base, size), _irq(irq)
: _reg(base, size), _irq(irq),
_dispatcher(ep, *this, &Gpio_bank::_handle)
{
for (unsigned i = 0; i < MAX_PINS; i++)
_irq_enabled[i] = false;
start();
}
void entry()
{
unsigned long status;
while (true) {
_reg.write<Gpio_reg::Irqstatus_0>(0xffffffff);
_irq.wait_for_irq();
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.sigh(_dispatcher);
_irq.ack_irq();
}
Gpio_reg* regs() { return &_reg; }
@ -100,28 +102,71 @@ class Omap4_driver : public Gpio::Driver
_irq_enabled[pin] = enable;
}
void ack_irq(int pin) { PDBG("not implemented"); }
void sigh(int pin, Genode::Signal_context_capability cap) {
_sig_cap[pin] = cap; }
};
Server::Entrypoint &_ep;
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;
}
static Gpio_bank _gpio_bank[MAX_BANKS];
PERR("no Gpio_bank for pin %d available", gpio);
return 0;
}
int _gpio_bank_index(int gpio) { return gpio >> 5; }
int _gpio_index(int gpio) { return gpio & 0x1f; }
Omap4_driver()
Omap4_driver(Server::Entrypoint &ep)
:
_ep(ep),
_gpio_bank_0(_ep, Genode::Board_base::GPIO1_MMIO_BASE, Genode::Board_base::GPIO1_MMIO_SIZE,
Genode::Board_base::GPIO1_IRQ),
_gpio_bank_1(_ep, Genode::Board_base::GPIO2_MMIO_BASE, Genode::Board_base::GPIO2_MMIO_SIZE,
Genode::Board_base::GPIO2_IRQ),
_gpio_bank_2(_ep, Genode::Board_base::GPIO3_MMIO_BASE, Genode::Board_base::GPIO3_MMIO_SIZE,
Genode::Board_base::GPIO3_IRQ),
_gpio_bank_3(_ep, Genode::Board_base::GPIO4_MMIO_BASE, Genode::Board_base::GPIO4_MMIO_SIZE,
Genode::Board_base::GPIO4_IRQ),
_gpio_bank_4(_ep, Genode::Board_base::GPIO5_MMIO_BASE, Genode::Board_base::GPIO5_MMIO_SIZE,
Genode::Board_base::GPIO5_IRQ),
_gpio_bank_5(_ep, Genode::Board_base::GPIO6_MMIO_BASE, Genode::Board_base::GPIO6_MMIO_SIZE,
Genode::Board_base::GPIO6_IRQ)
{
for (int i = 0; i < MAX_BANKS; ++i) {
if (verbose)
PDBG("GPIO%d ctrl=%08x",
i+1, _gpio_bank[i].regs()->read<Gpio_reg::Ctrl>());
i+1, _gpio_bank(i << PIN_SHIFT)->regs()->read<Gpio_reg::Ctrl>());
}
}
public:
static Omap4_driver& factory();
static Omap4_driver& factory(Server::Entrypoint &ep);
/******************************
@ -132,7 +177,7 @@ class Omap4_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d input=%d", gpio, input);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Oe>(input ? 1 : 0, _gpio_index(gpio));
}
@ -140,7 +185,7 @@ class Omap4_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d level=%d", gpio, level);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
if (level)
gpio_reg->write<Gpio_reg::Setdataout>(1 << _gpio_index(gpio));
@ -152,7 +197,7 @@ class Omap4_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d", gpio);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
return gpio_reg->read<Gpio_reg::Datain>(_gpio_index(gpio));
}
@ -160,7 +205,7 @@ class Omap4_driver : public Gpio::Driver
{
if (verbose) PDBG("gpio=%d enable=%d", gpio, enable);
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Debounceenable>(enable ? 1 : 0,
_gpio_index(gpio));
}
@ -178,7 +223,7 @@ class Omap4_driver : public Gpio::Driver
else
debounce = (us / 0x1f) - 1;
Gpio_reg *gpio_reg = _gpio_bank[_gpio_bank_index(gpio)].regs();
Gpio_reg *gpio_reg = _gpio_bank(gpio)->regs();
gpio_reg->write<Gpio_reg::Debouncingtime::Time>(debounce);
}
@ -186,7 +231,7 @@ class Omap4_driver : public Gpio::Driver
{