mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
i2c: command list format, get boot down to linker errors
This commit is contained in:
parent
42caa4ffd1
commit
258cfb62a2
13 changed files with 233 additions and 50 deletions
|
@ -17,6 +17,7 @@
|
|||
#pragma once
|
||||
#include <stratosphere/i2c/i2c_types.hpp>
|
||||
#include <stratosphere/i2c/i2c_select_device_name.hpp>
|
||||
#include <stratosphere/i2c/i2c_command_list_formatter.hpp>
|
||||
#include <stratosphere/i2c/sf/i2c_sf_i_session.hpp>
|
||||
#include <stratosphere/i2c/sf/i2c_sf_i_manager.hpp>
|
||||
#include <stratosphere/i2c/server/i2c_server_api.hpp>
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/i2c/i2c_types.hpp>
|
||||
|
||||
namespace ams::i2c {
|
||||
|
||||
constexpr inline size_t CommandListLengthMax = 0x100;
|
||||
constexpr inline size_t CommandListReceiveCommandSize = 2;
|
||||
constexpr inline size_t CommandListSendCommandSize = 2;
|
||||
constexpr inline size_t CommandListSleepCommandSize = 2;
|
||||
|
||||
class CommandListFormatter {
|
||||
NON_COPYABLE(CommandListFormatter);
|
||||
NON_MOVEABLE(CommandListFormatter);
|
||||
private:
|
||||
size_t current_index;
|
||||
size_t command_list_length;
|
||||
void *command_list;
|
||||
private:
|
||||
Result IsEnqueueAble(size_t sz) const;
|
||||
public:
|
||||
CommandListFormatter(void *p, size_t sz) : current_index(0), command_list_length(sz), command_list(p) {
|
||||
AMS_ABORT_UNLESS(this->command_list_length <= CommandListLengthMax);
|
||||
}
|
||||
|
||||
~CommandListFormatter() { this->command_list = nullptr; }
|
||||
|
||||
size_t GetCurrentLength() const { return this->current_index; }
|
||||
const void *GetListHead() const { return this->command_list; }
|
||||
|
||||
Result EnqueueReceiveCommand(i2c::TransactionOption option, size_t size);
|
||||
Result EnqueueSendCommand(i2c::TransactionOption option, const void *src, size_t size);
|
||||
Result EnqueueSleepCommand(int us);
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "impl/i2c_command_list_format.hpp"
|
||||
|
||||
namespace ams::i2c {
|
||||
|
||||
Result CommandListFormatter::IsEnqueueAble(size_t sz) const {
|
||||
R_UNLESS(this->command_list_length - this->current_index >= sz, ResultCommandListFull());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CommandListFormatter::EnqueueReceiveCommand(i2c::TransactionOption option, size_t size) {
|
||||
/* Check that we can enqueue the command. */
|
||||
constexpr size_t CommandLength = 2;
|
||||
R_TRY(this->IsEnqueueAble(CommandLength));
|
||||
|
||||
/* Get the command list. */
|
||||
util::BitPack8 *cmd_list = static_cast<util::BitPack8 *>(this->command_list);
|
||||
|
||||
/* Get references to the header. */
|
||||
auto &header0 = cmd_list[this->current_index++];
|
||||
auto &header1 = cmd_list[this->current_index++];
|
||||
|
||||
/* Set the header. */
|
||||
header0.Set<impl::CommonCommandFormat::CommandId>(impl::CommandId_Receive);
|
||||
header0.Set<impl::ReceiveCommandFormat::StopCondition>((option & TransactionOption_StopCondition) != 0);
|
||||
header0.Set<impl::ReceiveCommandFormat::StartCondition>((option & TransactionOption_StartCondition) != 0);
|
||||
|
||||
header1.Set<impl::ReceiveCommandFormat::Size>(size);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CommandListFormatter::EnqueueSendCommand(i2c::TransactionOption option, const void *src, size_t size) {
|
||||
/* Check that we can enqueue the command. */
|
||||
constexpr size_t CommandLength = 2;
|
||||
R_TRY(this->IsEnqueueAble(CommandLength + size));
|
||||
|
||||
/* Get the command list. */
|
||||
util::BitPack8 *cmd_list = static_cast<util::BitPack8 *>(this->command_list);
|
||||
|
||||
/* Get references to the header. */
|
||||
auto &header0 = cmd_list[this->current_index++];
|
||||
auto &header1 = cmd_list[this->current_index++];
|
||||
|
||||
/* Set the header. */
|
||||
header0.Set<impl::CommonCommandFormat::CommandId>(impl::CommandId_Send);
|
||||
header0.Set<impl::SendCommandFormat::StopCondition>((option & TransactionOption_StopCondition) != 0);
|
||||
header0.Set<impl::SendCommandFormat::StartCondition>((option & TransactionOption_StartCondition) != 0);
|
||||
|
||||
header1.Set<impl::SendCommandFormat::Size>(size);
|
||||
|
||||
/* Copy the data we're sending. */
|
||||
std::memcpy(cmd_list + this->current_index, src, size);
|
||||
this->current_index += size;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CommandListFormatter::EnqueueSleepCommand(int us) {
|
||||
/* Check that we can enqueue the command. */
|
||||
constexpr size_t CommandLength = 2;
|
||||
R_TRY(this->IsEnqueueAble(CommandLength));
|
||||
|
||||
/* Get the command list. */
|
||||
util::BitPack8 *cmd_list = static_cast<util::BitPack8 *>(this->command_list);
|
||||
|
||||
/* Get references to the header. */
|
||||
auto &header0 = cmd_list[this->current_index++];
|
||||
auto &header1 = cmd_list[this->current_index++];
|
||||
|
||||
/* Set the header. */
|
||||
header0.Set<impl::CommonCommandFormat::CommandId>(impl::CommandId_Extension);
|
||||
header0.Set<impl::CommonCommandFormat::SubCommandId>(impl::SubCommandId_Sleep);
|
||||
|
||||
header1.Set<impl::SleepCommandFormat::MicroSeconds>(us);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::i2c::impl {
|
||||
|
||||
enum CommandId {
|
||||
CommandId_Send = 0,
|
||||
CommandId_Receive = 1,
|
||||
CommandId_Extension = 2,
|
||||
CommandId_Count = 3,
|
||||
};
|
||||
|
||||
enum SubCommandId {
|
||||
SubCommandId_Sleep = 0,
|
||||
};
|
||||
|
||||
struct CommonCommandFormat {
|
||||
using CommandId = util::BitPack8::Field<0, 2>;
|
||||
using SubCommandId = util::BitPack8::Field<2, 6>;
|
||||
};
|
||||
|
||||
struct ReceiveCommandFormat {
|
||||
using StartCondition = util::BitPack8::Field<6, 1, bool>;
|
||||
using StopCondition = util::BitPack8::Field<7, 1, bool>;
|
||||
using Size = util::BitPack8::Field<0, 8>;
|
||||
};
|
||||
|
||||
struct SendCommandFormat {
|
||||
using StartCondition = util::BitPack8::Field<6, 1, bool>;
|
||||
using StopCondition = util::BitPack8::Field<7, 1, bool>;
|
||||
using Size = util::BitPack8::Field<0, 8>;
|
||||
};
|
||||
|
||||
struct SleepCommandFormat {
|
||||
using MicroSeconds = util::BitPack8::Field<0, 8>;
|
||||
};
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@ namespace ams::i2c {
|
|||
|
||||
R_DEFINE_ERROR_RESULT(NoAck, 1);
|
||||
R_DEFINE_ERROR_RESULT(BusBusy, 2);
|
||||
R_DEFINE_ERROR_RESULT(FullCommandList, 3);
|
||||
R_DEFINE_ERROR_RESULT(CommandListFull, 3);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(UnknownDevice, 5);
|
||||
|
||||
|
|
|
@ -14,22 +14,19 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "i2c/driver/i2c_api.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
class BatteryDriver {
|
||||
private:
|
||||
i2c::driver::Session i2c_session;
|
||||
i2c::driver::I2cSession i2c_session;
|
||||
public:
|
||||
BatteryDriver() {
|
||||
i2c::driver::Initialize();
|
||||
i2c::driver::OpenSession(&this->i2c_session, I2cDevice_Max17050);
|
||||
i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Max17050);
|
||||
}
|
||||
|
||||
~BatteryDriver() {
|
||||
i2c::driver::CloseSession(this->i2c_session);
|
||||
i2c::driver::Finalize();
|
||||
}
|
||||
private:
|
||||
Result Read(u8 addr, u16 *out_data);
|
||||
|
|
|
@ -23,11 +23,10 @@ namespace ams::boot {
|
|||
private:
|
||||
static constexpr u32 GpioPadName_Bq24193Charger = 0xA;
|
||||
private:
|
||||
i2c::driver::Session i2c_session;
|
||||
i2c::driver::I2cSession i2c_session;
|
||||
public:
|
||||
ChargerDriver() {
|
||||
i2c::driver::Initialize();
|
||||
i2c::driver::OpenSession(&this->i2c_session, I2cDevice_Bq24193);
|
||||
i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Bq24193);
|
||||
|
||||
//boot::gpio::Configure(GpioPadName_Bq24193Charger);
|
||||
//boot::gpio::SetDirection(GpioPadName_Bq24193Charger, GpioDirection_Output);
|
||||
|
@ -35,7 +34,6 @@ namespace ams::boot {
|
|||
|
||||
~ChargerDriver() {
|
||||
i2c::driver::CloseSession(this->i2c_session);
|
||||
i2c::driver::Finalize();
|
||||
}
|
||||
private:
|
||||
Result Read(u8 addr, u8 *out_data);
|
||||
|
|
|
@ -196,11 +196,8 @@ namespace ams::boot {
|
|||
|
||||
/* Turn on DSI/voltage rail. */
|
||||
{
|
||||
i2c::driver::Session i2c_session;
|
||||
i2c::driver::Initialize();
|
||||
ON_SCOPE_EXIT { i2c::driver::Finalize(); };
|
||||
|
||||
i2c::driver::OpenSession(&i2c_session, I2cDevice_Max77620Pmic);
|
||||
i2c::driver::I2cSession i2c_session;
|
||||
i2c::driver::OpenSession(std::addressof(i2c_session), i2c::DeviceCode_Max77620Pmic);
|
||||
|
||||
if (g_soc_type == spl::SocType_Mariko) {
|
||||
WriteI2cRegister(i2c_session, 0x18, 0x3A);
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace ams::boot {
|
|||
/* TODO: pwm::driver::board::Initialize(); */
|
||||
|
||||
/* Initialize the pwm driver library. */
|
||||
/* TODO: pwm::driver::Initialize();
|
||||
/* TODO: pwm::driver::Initialize(); */
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,54 +22,51 @@ namespace ams::boot {
|
|||
|
||||
template<typename F>
|
||||
constexpr Result RetryUntilSuccess(F f) {
|
||||
constexpr u64 timeout = 10'000'000'000ul;
|
||||
constexpr u64 retry_interval = 20'000'000ul;
|
||||
constexpr auto Timeout = TimeSpan::FromSeconds(10);
|
||||
constexpr auto RetryInterval = TimeSpan::FromMilliSeconds(20);
|
||||
|
||||
u64 cur_time = 0;
|
||||
TimeSpan cur_time = TimeSpan(0);
|
||||
while (true) {
|
||||
const auto retry_result = f();
|
||||
R_SUCCEED_IF(R_SUCCEEDED(retry_result));
|
||||
|
||||
cur_time += retry_interval;
|
||||
if (cur_time < timeout) {
|
||||
svcSleepThread(retry_interval);
|
||||
continue;
|
||||
}
|
||||
cur_time += RetryInterval;
|
||||
R_UNLESS(cur_time < Timeout, retry_result);
|
||||
|
||||
return retry_result;
|
||||
os::SleepThread(RetryInterval);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result ReadI2cRegister(i2c::driver::Session &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size) {
|
||||
Result ReadI2cRegister(i2c::driver::I2cSession &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size) {
|
||||
AMS_ABORT_UNLESS(dst != nullptr && dst_size > 0);
|
||||
AMS_ABORT_UNLESS(cmd != nullptr && cmd_size > 0);
|
||||
|
||||
u8 cmd_list[i2c::CommandListFormatter::MaxCommandListSize];
|
||||
|
||||
u8 cmd_list[i2c::CommandListLengthMax];
|
||||
i2c::CommandListFormatter formatter(cmd_list, sizeof(cmd_list));
|
||||
R_ABORT_UNLESS(formatter.EnqueueSendCommand(I2cTransactionOption_Start, cmd, cmd_size));
|
||||
R_ABORT_UNLESS(formatter.EnqueueReceiveCommand(static_cast<I2cTransactionOption>(I2cTransactionOption_Start | I2cTransactionOption_Stop), dst_size));
|
||||
|
||||
return RetryUntilSuccess([&]() { return i2c::driver::ExecuteCommandList(session, dst, dst_size, cmd_list, formatter.GetCurrentSize()); });
|
||||
R_ABORT_UNLESS(formatter.EnqueueSendCommand(i2c::TransactionOption_StartCondition, cmd, cmd_size));
|
||||
R_ABORT_UNLESS(formatter.EnqueueReceiveCommand(static_cast<i2c::TransactionOption>(i2c::TransactionOption_StartCondition | i2c::TransactionOption_StopCondition), dst_size));
|
||||
|
||||
return RetryUntilSuccess([&]() { return i2c::driver::ExecuteCommandList(dst, dst_size, session, cmd_list, formatter.GetCurrentLength()); });
|
||||
}
|
||||
|
||||
Result WriteI2cRegister(i2c::driver::Session &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size) {
|
||||
Result WriteI2cRegister(i2c::driver::I2cSession &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size) {
|
||||
AMS_ABORT_UNLESS(src != nullptr && src_size > 0);
|
||||
AMS_ABORT_UNLESS(cmd != nullptr && cmd_size > 0);
|
||||
|
||||
u8 cmd_list[0x20];
|
||||
|
||||
/* N doesn't use a CommandListFormatter here... */
|
||||
std::memcpy(&cmd_list[0], cmd, cmd_size);
|
||||
std::memcpy(&cmd_list[cmd_size], src, src_size);
|
||||
std::memcpy(cmd_list + 0, cmd, cmd_size);
|
||||
std::memcpy(cmd_list + cmd_size, src, src_size);
|
||||
|
||||
return RetryUntilSuccess([&]() { return i2c::driver::Send(session, cmd_list, src_size + cmd_size, static_cast<I2cTransactionOption>(I2cTransactionOption_Start | I2cTransactionOption_Stop)); });
|
||||
return RetryUntilSuccess([&]() { return i2c::driver::Send(session, cmd_list, src_size + cmd_size, static_cast<i2c::TransactionOption>(i2c::TransactionOption_StartCondition | i2c::TransactionOption_StopCondition)); });
|
||||
}
|
||||
|
||||
Result WriteI2cRegister(i2c::driver::Session &session, const u8 address, const u8 value) {
|
||||
return WriteI2cRegister(session, &value, sizeof(value), &address, sizeof(address));
|
||||
Result WriteI2cRegister(i2c::driver::I2cSession &session, const u8 address, const u8 value) {
|
||||
return WriteI2cRegister(session, std::addressof(value), sizeof(value), &address, sizeof(address));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,13 +16,11 @@
|
|||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "i2c/driver/i2c_api.hpp"
|
||||
|
||||
namespace ams::boot {
|
||||
|
||||
/* I2C Utilities. */
|
||||
Result ReadI2cRegister(i2c::driver::Session &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size);
|
||||
Result WriteI2cRegister(i2c::driver::Session &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size);
|
||||
Result WriteI2cRegister(i2c::driver::Session &session, const u8 address, const u8 value);
|
||||
Result ReadI2cRegister(i2c::driver::I2cSession &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size);
|
||||
Result WriteI2cRegister(i2c::driver::I2cSession &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size);
|
||||
Result WriteI2cRegister(i2c::driver::I2cSession &session, const u8 address, const u8 value);
|
||||
|
||||
}
|
||||
|
|
|
@ -21,16 +21,14 @@ namespace ams::boot {
|
|||
/* Driver object. */
|
||||
class PmicDriver {
|
||||
private:
|
||||
i2c::driver::Session i2c_session;
|
||||
i2c::driver::I2cSession i2c_session;
|
||||
public:
|
||||
PmicDriver() {
|
||||
i2c::driver::Initialize();
|
||||
i2c::driver::OpenSession(&this->i2c_session, I2cDevice_Max77620Pmic);
|
||||
i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Max77620Pmic);
|
||||
}
|
||||
|
||||
~PmicDriver() {
|
||||
i2c::driver::CloseSession(this->i2c_session);
|
||||
i2c::driver::Finalize();
|
||||
}
|
||||
private:
|
||||
Result GetPowerStatus(u8 *out);
|
||||
|
|
|
@ -20,16 +20,14 @@ namespace ams::boot {
|
|||
|
||||
class RtcDriver {
|
||||
private:
|
||||
i2c::driver::Session i2c_session;
|
||||
i2c::driver::I2cSession i2c_session;
|
||||
public:
|
||||
RtcDriver() {
|
||||
i2c::driver::Initialize();
|
||||
i2c::driver::OpenSession(&this->i2c_session, I2cDevice_Max77620Rtc);
|
||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Max77620Rtc));
|
||||
}
|
||||
|
||||
~RtcDriver() {
|
||||
i2c::driver::CloseSession(this->i2c_session);
|
||||
i2c::driver::Finalize();
|
||||
}
|
||||
private:
|
||||
Result ReadRtcRegister(u8 *out, u8 address);
|
||||
|
|
Loading…
Reference in a new issue