mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
ahci: remove Exynos5 support
Exynos5 support has ceased on Genode issue #3636
This commit is contained in:
parent
de24035066
commit
73f2c7043c
@ -1,400 +0,0 @@
|
||||
/*
|
||||
* \brief Driver for Exynos-5250 soc
|
||||
* \author Martin Stein
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-05-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 <drivers/defs/exynos5.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <regulator/consts.h>
|
||||
#include <regulator_session/connection.h>
|
||||
|
||||
#include <ahci.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
/**
|
||||
* I2C master interface
|
||||
*/
|
||||
struct I2c_interface : Attached_mmio
|
||||
{
|
||||
enum { TX_DELAY_US = 1 };
|
||||
|
||||
/********************************
|
||||
** MMIO structure description **
|
||||
********************************/
|
||||
|
||||
struct Start_msg : Genode::Register<8>
|
||||
{
|
||||
struct Addr : Bitfield<1, 7> { };
|
||||
};
|
||||
|
||||
struct Con : Register<0x0, 8>
|
||||
{
|
||||
struct Tx_prescaler : Bitfield<0, 4> { };
|
||||
struct Irq_pending : Bitfield<4, 1> { };
|
||||
struct Irq_en : Bitfield<5, 1> { };
|
||||
struct Clk_sel : Bitfield<6, 1> { };
|
||||
struct Ack_en : Bitfield<7, 1> { };
|
||||
};
|
||||
|
||||
struct Stat : Register<0x4, 8>
|
||||
{
|
||||
struct Last_bit : Bitfield<0, 1> { };
|
||||
struct Arbitr : Bitfield<3, 1> { };
|
||||
struct Txrx_en : Bitfield<4, 1> { };
|
||||
struct Busy : Bitfield<5, 1> { };
|
||||
struct Mode : Bitfield<6, 2> { };
|
||||
};
|
||||
|
||||
struct Add : Register<0x8, 8>
|
||||
{
|
||||
struct Slave_addr : Bitfield<0, 8> { };
|
||||
};
|
||||
|
||||
struct Ds : Register<0xc, 8> { };
|
||||
|
||||
struct Lc : Register<0x10, 8>
|
||||
{
|
||||
struct Sda_out_delay : Bitfield<0, 2> { };
|
||||
struct Filter_en : Bitfield<2, 1> { };
|
||||
};
|
||||
|
||||
Mmio::Delayer &delayer;
|
||||
/* single-word message that starts a multi-word message transfer */
|
||||
Start_msg::access_t const start_msg;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param base physical MMIO base
|
||||
* \param slave_addr ID of the targeted slave
|
||||
*/
|
||||
I2c_interface(Genode::Env &env,
|
||||
addr_t base, unsigned slave_addr, Mmio::Delayer &delayer)
|
||||
: Attached_mmio(env, base, 0x10000), delayer(delayer),
|
||||
start_msg(Start_msg::Addr::bits(slave_addr))
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Wether acknowledgment for last transaction can be received
|
||||
*/
|
||||
bool ack_received()
|
||||
{
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
if (read<Con::Irq_pending>() && !read<Stat::Last_bit>()) return 1;
|
||||
delayer.usleep(TX_DELAY_US);
|
||||
}
|
||||
Genode::error("I2C ack not received");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wether arbitration errors occured during the last transaction
|
||||
*/
|
||||
bool arbitration_error()
|
||||
{
|
||||
if (read<Stat::Arbitr>()) {
|
||||
Genode::error("I2C arbitration failed");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Let I2C master send a message to I2C slave
|
||||
*
|
||||
* \param msg message base
|
||||
* \param msg_size message size
|
||||
*
|
||||
* \retval 0 call was successful
|
||||
* \retval <0 call failed, error code
|
||||
*/
|
||||
int send(uint8_t * msg, size_t msg_size)
|
||||
{
|
||||
/* initiate message transfer */
|
||||
try {
|
||||
wait_for(delayer, Stat::Busy::Equal(0));
|
||||
} catch (Polling_timeout) {
|
||||
Genode::error("I2C busy");
|
||||
return -1;
|
||||
}
|
||||
Stat::access_t stat = read<Stat>();
|
||||
Stat::Txrx_en::set(stat, 1);
|
||||
Stat::Mode::set(stat, 3);
|
||||
write<Stat>(stat);
|
||||
write<Ds>(start_msg);
|
||||
delayer.usleep(1000);
|
||||
write<Con::Tx_prescaler>(11);
|
||||
write<Stat::Busy>(1);
|
||||
|
||||
/* transmit message payload */
|
||||
for (unsigned i = 0; i < msg_size; i++) {
|
||||
if (!ack_received()) return -1;
|
||||
write<Ds>(msg[i]);
|
||||
delayer.usleep(TX_DELAY_US);
|
||||
write<Con::Irq_pending>(0);
|
||||
if (arbitration_error()) return -1;
|
||||
}
|
||||
/* end message transfer */
|
||||
if (!ack_received()) return -1;
|
||||
write<Stat::Busy>(0);
|
||||
write<Con::Irq_en>(0);
|
||||
write<Con::Irq_pending>(0); /* FIXME fixup */
|
||||
if (arbitration_error()) return -1;
|
||||
try {
|
||||
wait_for(delayer, Stat::Busy::Equal(0));
|
||||
} catch (Polling_timeout) {
|
||||
Genode::error("I2C end transfer failed");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* I2C control interface of SATA PHY-layer controller
|
||||
*/
|
||||
struct I2c_sataphy : I2c_interface
|
||||
{
|
||||
enum { SLAVE_ADDR = 0x38 };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
I2c_sataphy(Genode::Env &env, Mmio::Delayer &delayer)
|
||||
: I2c_interface(env, 0x121d0000, SLAVE_ADDR, delayer)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Enable the 40-pin interface of the SATA PHY controller
|
||||
*
|
||||
* \retval 0 call was successful
|
||||
* \retval <0 call failed, error code
|
||||
*/
|
||||
int enable_40_pins()
|
||||
{
|
||||
/*
|
||||
* I2C message
|
||||
*
|
||||
* first byte: set address
|
||||
* second byte: set data
|
||||
*/
|
||||
static uint8_t msg[] = { 0x3a, 0x0b };
|
||||
enum { MSG_SIZE = sizeof(msg)/sizeof(msg[0]) };
|
||||
|
||||
/* send messaage */
|
||||
if (send(msg, MSG_SIZE)) return -1;
|
||||
if (verbose) Genode::log("SATA PHY 40-pin interface enabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I2C interface ready for transmissions
|
||||
*/
|
||||
void init()
|
||||
{
|
||||
write<Add::Slave_addr>(SLAVE_ADDR);
|
||||
|
||||
Con::access_t con = read<Con>();
|
||||
Con::Irq_en::set(con, 1);
|
||||
Con::Ack_en::set(con, 1);
|
||||
Con::Clk_sel::set(con, 1);
|
||||
Con::Tx_prescaler::set(con, 9);
|
||||
write<Con>(con);
|
||||
|
||||
Lc::access_t lc = 0;
|
||||
Lc::Sda_out_delay::set(lc, 3);
|
||||
Lc::Filter_en::set(lc, 1);
|
||||
write<Lc>(lc);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Classical control interface of SATA PHY-layer controller
|
||||
*/
|
||||
struct Sata_phy_ctrl : Attached_mmio
|
||||
{
|
||||
Mmio::Delayer &delayer;
|
||||
I2c_sataphy i2c_sataphy;
|
||||
|
||||
/********************************
|
||||
** MMIO structure description **
|
||||
********************************/
|
||||
|
||||
struct Reset : Register<0x4, 32>
|
||||
{
|
||||
struct Global : Bitfield<1, 1> { };
|
||||
struct Non_link : Bitfield<0, 8> { };
|
||||
struct Link : Bitfield<16, 4> { };
|
||||
};
|
||||
|
||||
struct Mode0 : Register<0x10, 32>
|
||||
{
|
||||
struct P0_phy_spdmode : Bitfield<0, 2> { };
|
||||
};
|
||||
|
||||
struct Ctrl0 : Register<0x14, 32>
|
||||
{
|
||||
struct P0_phy_calibrated : Bitfield<8, 1> { };
|
||||
struct P0_phy_calibrated_sel : Bitfield<9, 1> { };
|
||||
};
|
||||
|
||||
struct Phctrlm : Register<0xe0, 32>
|
||||
{
|
||||
struct High_speed : Bitfield<0, 1> { };
|
||||
struct Ref_rate : Bitfield<1, 1> { };
|
||||
};
|
||||
|
||||
struct Phstatm : Register<0xf0, 32>
|
||||
{
|
||||
struct Pll_locked : Bitfield<0, 1> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Sata_phy_ctrl(Genode::Env &env, Mmio::Delayer &delayer)
|
||||
:
|
||||
Attached_mmio(env, 0x12170000, 0x10000), delayer(delayer),
|
||||
i2c_sataphy(env, delayer)
|
||||
{
|
||||
i2c_sataphy.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize parts of SATA PHY that are controlled classically
|
||||
*
|
||||
* \retval 0 call was successful
|
||||
* \retval <0 call failed, error code
|
||||
*/
|
||||
int init()
|
||||
{
|
||||
/* reset */
|
||||
write<Reset>(0);
|
||||
write<Reset::Non_link>(~0);
|
||||
write<Reset::Link>(~0);
|
||||
write<Reset::Global>(~0);
|
||||
|
||||
/* set up SATA phy generation 3 (6 Gb/s) */
|
||||
Phctrlm::access_t phctrlm = read<Phctrlm>();
|
||||
Phctrlm::Ref_rate::set(phctrlm, 0);
|
||||
Phctrlm::High_speed::set(phctrlm, 1);
|
||||
write<Phctrlm>(phctrlm);
|
||||
Ctrl0::access_t ctrl0 = read<Ctrl0>();
|
||||
Ctrl0::P0_phy_calibrated::set(ctrl0, 1);
|
||||
Ctrl0::P0_phy_calibrated_sel::set(ctrl0, 1);
|
||||
write<Ctrl0>(ctrl0);
|
||||
write<Mode0::P0_phy_spdmode>(2);
|
||||
if (i2c_sataphy.enable_40_pins()) return -1;
|
||||
|
||||
/* Release reset */
|
||||
write<Reset::Global>(0);
|
||||
write<Reset::Global>(1);
|
||||
|
||||
/*
|
||||
* FIXME Linux reads this bit once only and continues
|
||||
* directly, also with zero. So if we get an error
|
||||
* at this point we should study the Linux behavior
|
||||
* in more depth.
|
||||
*/
|
||||
try {
|
||||
wait_for(delayer, Phstatm::Pll_locked::Equal(1));
|
||||
} catch (Polling_timeout) {
|
||||
Genode::error("PLL lock failed");
|
||||
return -1;
|
||||
}
|
||||
if (verbose)
|
||||
Genode::log("SATA PHY initialized");
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Exynos5_hba : Platform::Hba
|
||||
{
|
||||
Genode::Env &env;
|
||||
|
||||
Irq_connection irq { env, Exynos5::SATA_IRQ };
|
||||
Regulator::Connection clock_src { env, Regulator::CLK_SATA };
|
||||
Regulator::Connection power_src { env, Regulator::PWR_SATA };
|
||||
|
||||
Exynos5_hba(Genode::Env &env, Mmio::Delayer &delayer)
|
||||
: env(env)
|
||||
{
|
||||
clock_src.state(true);
|
||||
power_src.state(true);
|
||||
|
||||
Sata_phy_ctrl phy(env, delayer);
|
||||
|
||||
if (phy.init())
|
||||
throw Service_denied();
|
||||
|
||||
/* additionally perform some generic initializations */
|
||||
::Hba hba(env, *this, delayer);
|
||||
|
||||
::Hba::Cap::access_t cap = hba.read< ::Hba::Cap>();
|
||||
::Hba::Cap2::access_t cap2 = hba.read< ::Hba::Cap2>();
|
||||
|
||||
/* reset */
|
||||
hba.write< ::Hba::Ghc::Hr>(1);
|
||||
try {
|
||||
hba.wait_for(::Hba::Attempts(1000), ::Hba::Microseconds(1000),
|
||||
hba.delayer(), ::Hba::Ghc::Hr::Equal(0));
|
||||
} catch (::Hba::Polling_timeout) {
|
||||
Genode::error("HBA reset failed");
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
hba.write< ::Hba::Cap>(cap);
|
||||
hba.write< ::Hba::Cap2>(cap2);
|
||||
|
||||
/* for exynos set port 0 as implemented, usally set by BIOS */
|
||||
hba.write< ::Hba::Pi>(0x1);
|
||||
}
|
||||
|
||||
|
||||
/*******************
|
||||
** Hba interface **
|
||||
*******************/
|
||||
|
||||
Genode::addr_t base() const override { return 0x122f0000; }
|
||||
Genode::size_t size() const override { return 0x10000; }
|
||||
|
||||
void sigh_irq(Signal_context_capability sigh) override
|
||||
{
|
||||
irq.sigh(sigh);
|
||||
ack_irq();
|
||||
}
|
||||
|
||||
void ack_irq() override { irq.ack_irq(); }
|
||||
|
||||
Ram_dataspace_capability
|
||||
alloc_dma_buffer(size_t size) override
|
||||
{
|
||||
return env.ram().alloc(size, UNCACHED);
|
||||
}
|
||||
|
||||
void free_dma_buffer(Ram_dataspace_capability ds) override
|
||||
{
|
||||
env.ram().free(ds);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Platform::Hba &Platform::init(Genode::Env &env, Mmio::Delayer &delayer)
|
||||
{
|
||||
static Exynos5_hba h(env, delayer);
|
||||
return h;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
TARGET = exynos5_ahci_drv
|
||||
REQUIRES = arm_v7
|
||||
INC_DIR = $(call select_from_repositories,include/spec/exynos5)
|
||||
|
||||
include $(REP_DIR)/src/drivers/ahci/target.inc
|
Loading…
x
Reference in New Issue
Block a user