| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <ddk/binding.h> |
| #include <ddk/debug.h> |
| #include <ddk/device.h> |
| #include <ddk/metadata.h> |
| #include <ddk/metadata/i2c.h> |
| #include <ddk/metadata/power.h> |
| #include <ddk/platform-defs.h> |
| #include <soc/aml-common/aml-power.h> |
| #include <soc/aml-t931/t931-gpio.h> |
| #include <soc/aml-t931/t931-power.h> |
| #include <soc/aml-t931/t931-pwm.h> |
| |
| #include "sherlock.h" |
| |
| namespace sherlock { |
| |
| namespace { |
| |
| constexpr uint32_t kPwmDFn = 3; |
| |
| constexpr aml_voltage_table_t kT931VoltageTable[] = { |
| {1'022'000, 0}, {1'011'000, 3}, {1'001'000, 6}, {991'000, 10}, {981'000, 13}, {971'000, 16}, |
| {961'000, 20}, {951'000, 23}, {941'000, 26}, {931'000, 30}, {921'000, 33}, {911'000, 36}, |
| {901'000, 40}, {891'000, 43}, {881'000, 46}, {871'000, 50}, {861'000, 53}, {851'000, 56}, |
| {841'000, 60}, {831'000, 63}, {821'000, 67}, {811'000, 70}, {801'000, 73}, {791'000, 76}, |
| {781'000, 80}, {771'000, 83}, {761'000, 86}, {751'000, 90}, {741'000, 93}, {731'000, 96}, |
| {721'000, 100}, |
| }; |
| |
| constexpr voltage_pwm_period_ns_t kT931PwmPeriodNs = 1250; |
| |
| constexpr pbus_metadata_t power_impl_metadata[] = { |
| { |
| .type = DEVICE_METADATA_AML_VOLTAGE_TABLE, |
| .data_buffer = &kT931VoltageTable, |
| .data_size = sizeof(kT931VoltageTable), |
| }, |
| { |
| .type = DEVICE_METADATA_AML_PWM_PERIOD_NS, |
| .data_buffer = &kT931PwmPeriodNs, |
| .data_size = sizeof(kT931PwmPeriodNs), |
| }, |
| }; |
| |
| constexpr zx_bind_inst_t root_match[] = { |
| BI_MATCH(), |
| }; |
| |
| constexpr zx_bind_inst_t power_impl_driver_match[] = { |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_POWER_IMPL), |
| }; |
| |
| constexpr device_fragment_part_t power_impl_fragment[] = { |
| {countof(root_match), root_match}, |
| {countof(power_impl_driver_match), power_impl_driver_match}, |
| }; |
| |
| zx_device_prop_t power_domain_arm_core_props[] = { |
| {BIND_POWER_DOMAIN_COMPOSITE, 0, PDEV_DID_POWER_DOMAIN_COMPOSITE}, |
| }; |
| |
| constexpr device_fragment_t power_domain_arm_core_fragments[] = { |
| {"power", countof(power_impl_fragment), power_impl_fragment}, |
| }; |
| |
| constexpr power_domain_t big_domain[] = { |
| {static_cast<uint32_t>(T931PowerDomains::kArmCoreBig)}, |
| }; |
| |
| constexpr device_metadata_t power_domain_big_core[] = { |
| { |
| .type = DEVICE_METADATA_POWER_DOMAINS, |
| .data = &big_domain, |
| .length = sizeof(big_domain), |
| }, |
| }; |
| |
| constexpr composite_device_desc_t power_domain_big_core_desc = { |
| .props = power_domain_arm_core_props, |
| .props_count = countof(power_domain_arm_core_props), |
| .fragments = power_domain_arm_core_fragments, |
| .fragments_count = countof(power_domain_arm_core_fragments), |
| .coresident_device_index = 0, |
| .metadata_list = power_domain_big_core, |
| .metadata_count = countof(power_domain_big_core), |
| }; |
| |
| constexpr power_domain_t little_domain[] = { |
| {static_cast<uint32_t>(T931PowerDomains::kArmCoreLittle)}, |
| }; |
| |
| constexpr device_metadata_t power_domain_little_core[] = { |
| { |
| .type = DEVICE_METADATA_POWER_DOMAINS, |
| .data = &little_domain, |
| .length = sizeof(little_domain), |
| }, |
| }; |
| |
| constexpr composite_device_desc_t power_domain_little_core_desc = { |
| .props = power_domain_arm_core_props, |
| .props_count = countof(power_domain_arm_core_props), |
| .fragments = power_domain_arm_core_fragments, |
| .fragments_count = countof(power_domain_arm_core_fragments), |
| .coresident_device_index = 0, |
| .metadata_list = power_domain_little_core, |
| .metadata_count = countof(power_domain_little_core), |
| }; |
| |
| constexpr zx_bind_inst_t pwm_ao_d_match[] = { |
| BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PWM), |
| BI_MATCH_IF(EQ, BIND_PWM_ID, T931_PWM_AO_D), |
| }; |
| |
| constexpr device_fragment_part_t pwm_ao_d_fragment[] = { |
| {countof(root_match), root_match}, |
| {countof(pwm_ao_d_match), pwm_ao_d_match}, |
| }; |
| |
| constexpr zx_bind_inst_t vreg_pp1000_cpu_a_match[] = { |
| BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_VREG), |
| BI_ABORT_IF(NE, BIND_I2C_BUS_ID, SHERLOCK_I2C_3), |
| BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, 0x60), |
| }; |
| |
| constexpr device_fragment_part_t vreg_pp1000_cpu_a_fragment[] = { |
| {countof(root_match), root_match}, |
| {countof(vreg_pp1000_cpu_a_match), vreg_pp1000_cpu_a_match}, |
| }; |
| |
| constexpr device_fragment_t power_impl_fragments[] = { |
| {"pwm-ao-d", countof(pwm_ao_d_fragment), pwm_ao_d_fragment}, |
| {"vreg-pp1000-cpu-a", countof(vreg_pp1000_cpu_a_fragment), vreg_pp1000_cpu_a_fragment}, |
| }; |
| |
| } // namespace |
| |
| static const pbus_dev_t power_dev = []() { |
| pbus_dev_t dev = {}; |
| dev.name = "aml-power-impl-composite"; |
| dev.vid = PDEV_VID_GOOGLE; |
| dev.pid = PDEV_PID_LUIS; |
| dev.did = PDEV_DID_AMLOGIC_POWER; |
| dev.metadata_list = power_impl_metadata; |
| dev.metadata_count = countof(power_impl_metadata); |
| return dev; |
| }(); |
| |
| zx_status_t Sherlock::LuisPowerPublishBuck(const char* name, uint32_t bus_id, uint16_t address) { |
| const zx_bind_inst_t i2c_match[] = { |
| BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C), |
| BI_ABORT_IF(NE, BIND_I2C_BUS_ID, bus_id), |
| BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, address), |
| }; |
| |
| const device_fragment_part_t i2c_fragment[] = { |
| {countof(root_match), root_match}, |
| {countof(i2c_match), i2c_match}, |
| }; |
| |
| const device_fragment_t fragments[] = { |
| {"i2c", countof(i2c_fragment), i2c_fragment}, |
| }; |
| |
| const zx_device_prop_t props[] = { |
| {BIND_PLATFORM_DEV_VID, 0, PDEV_VID_SILERGY}, |
| {BIND_PLATFORM_DEV_PID, 0, PDEV_PID_SILERGY_SYBUCK}, |
| }; |
| |
| const i2c_channel_t i2c_channels = { |
| .bus_id = bus_id, |
| .address = address, |
| }; |
| |
| const device_metadata_t metadata[] = { |
| { |
| .type = DEVICE_METADATA_I2C_CHANNELS, |
| .data = &i2c_channels, |
| .length = sizeof(i2c_channels), |
| }, |
| }; |
| |
| const composite_device_desc_t comp_desc = { |
| .props = props, |
| .props_count = countof(props), |
| .fragments = fragments, |
| .fragments_count = countof(fragments), |
| .coresident_device_index = 0, |
| .metadata_list = metadata, |
| .metadata_count = countof(metadata), |
| }; |
| |
| return DdkAddComposite(name, &comp_desc); |
| } |
| |
| zx_status_t Sherlock::LuisPowerInit() { |
| zx_status_t st; |
| |
| // Configure the GPIO to be Output & set it to alternate |
| // function 3 which puts in PWM_D mode. A53 cluster (Small) |
| gpio_impl_.SetAltFunction(T931_GPIOE(1), kPwmDFn); |
| |
| st = gpio_impl_.ConfigOut(T931_GPIOE(1), 0); |
| if (st != ZX_OK) { |
| zxlogf(ERROR, "%s: ConfigOut failed: %d", __func__, st); |
| return st; |
| } |
| |
| st = LuisPowerPublishBuck("0p8_ee_buck", SHERLOCK_I2C_A0_0, 0x60); |
| if (st != ZX_OK) { |
| zxlogf(ERROR, "Failed to publish sy8827 0P8_EE_BUCK device, st = %d", st); |
| return st; |
| } |
| |
| st = LuisPowerPublishBuck("cpu_a_buck", SHERLOCK_I2C_3, 0x60); |
| if (st != ZX_OK) { |
| zxlogf(ERROR, "Failed to publish sy8827 CPU_A_BUCK device, st = %d", st); |
| return st; |
| } |
| |
| st = pbus_.CompositeDeviceAdd(&power_dev, power_impl_fragments, countof(power_impl_fragments), |
| UINT32_MAX); |
| if (st != ZX_OK) { |
| zxlogf(ERROR, "%s: CompositeDeviceAdd for powerimpl failed, st = %d", __FUNCTION__, st); |
| return st; |
| } |
| |
| st = DdkAddComposite("composite-pd-big-core", &power_domain_big_core_desc); |
| if (st != ZX_OK) { |
| zxlogf(ERROR, "%s: CompositeDeviceAdd for power domain Big Arm Core failed, st = %d", |
| __FUNCTION__, st); |
| return st; |
| } |
| |
| st = DdkAddComposite("composite-pd-little-core", &power_domain_little_core_desc); |
| if (st != ZX_OK) { |
| zxlogf(ERROR, "%s: CompositeDeviceAdd for power domain Little Arm Core failed, st = %d", |
| __FUNCTION__, st); |
| return st; |
| } |
| |
| return ZX_OK; |
| } |
| |
| } // namespace sherlock |