blob: df4b77427e79ac84f4f61ef90e255852e7759556 [file] [log] [blame]
// Copyright 2019 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 <lib/mmio/mmio.h>
#include <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/metadata.h>
#include <ddk/metadata/spi.h>
#include <ddk/platform-defs.h>
#include <fbl/algorithm.h>
#include <soc/aml-common/aml-spi.h>
#include <soc/aml-s905d2/s905d2-gpio.h>
#include <soc/aml-s905d3/s905d3-hw.h>
#include "nelson-gpios.h"
#include "nelson.h"
#define HHI_SPICC_CLK_CNTL (0xf7 * 4)
#define spicc1_clk_sel_fclk_div2 (4 << 23)
#define spicc1_clk_en (1 << 22)
#define spicc1_clk_div(x) (((x)-1) << 16)
namespace nelson {
static const pbus_mmio_t spi_mmios[] = {
{
.base = S905D3_SPICC0_BASE,
.length = S905D3_SPICC0_LENGTH,
},
{
.base = S905D3_SPICC1_BASE,
.length = S905D3_SPICC1_LENGTH,
},
};
static const pbus_irq_t spi_irqs[] = {
{
.irq = S905D3_SPICC0_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
{
.irq = S905D3_SPICC1_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
};
static const spi_channel_t spi_channels[] = {
// Radar sensor head.
{
.bus_id = NELSON_SPICC1,
.cs = 0, // index into matching chip-select map
.vid = PDEV_VID_INFINEON,
.pid = PDEV_PID_INFINEON_BGT60TR13C,
.did = PDEV_DID_RADAR_SENSOR,
}};
static const amlspi_cs_map_t spi_cs_map[] = {
{.bus_id = NELSON_SPICC0, .cs_count = 0, .cs = {}}, // Unused.
{
.bus_id = NELSON_SPICC1, .cs_count = 1, .cs = {0} // index into fragments list
},
};
static const pbus_metadata_t spi_metadata[] = {
{
.type = DEVICE_METADATA_SPI_CHANNELS,
.data_buffer = spi_channels,
.data_size = sizeof spi_channels,
},
{
.type = DEVICE_METADATA_AMLSPI_CS_MAPPING,
.data_buffer = &spi_cs_map,
.data_size = sizeof spi_cs_map,
},
};
static pbus_dev_t spi_dev = []() {
pbus_dev_t dev = {};
dev.name = "spi";
dev.vid = PDEV_VID_AMLOGIC;
dev.pid = PDEV_PID_GENERIC;
dev.did = PDEV_DID_AMLOGIC_SPI;
dev.mmio_list = spi_mmios;
dev.mmio_count = countof(spi_mmios);
dev.irq_list = spi_irqs;
dev.irq_count = countof(spi_irqs);
dev.metadata_list = spi_metadata;
dev.metadata_count = countof(spi_metadata);
return dev;
}();
// composite binding rules
static const zx_bind_inst_t root_match[] = {
BI_MATCH(),
};
static constexpr zx_bind_inst_t gpio_spicc1_ss0_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_SPICC1_SS0),
};
static constexpr device_fragment_part_t gpio_spicc1_ss0_fragment[] = {
{fbl::count_of(root_match), root_match},
{fbl::count_of(gpio_spicc1_ss0_match), gpio_spicc1_ss0_match},
};
static constexpr device_fragment_t fragments[] = {
{fbl::count_of(gpio_spicc1_ss0_fragment), gpio_spicc1_ss0_fragment},
};
zx_status_t Nelson::SpiInit() {
// setup pinmux for SPICC1 bus arbiter.
gpio_impl_.SetAltFunction(S905D2_GPIOH(4), 3); // MOSI
gpio_impl_.SetAltFunction(S905D2_GPIOH(5), 3); // MISO
gpio_impl_.ConfigOut(GPIO_SPICC1_SS0, 1); // SS0
gpio_impl_.ConfigIn(S905D2_GPIOH(7), GPIO_PULL_DOWN); // SCLK
gpio_impl_.SetAltFunction(S905D2_GPIOH(7), 3); // SCLK
// TODO(ZX-4230): fix this clock enable block when the clock driver can handle the dividers
{
// Please do not use get_root_resource() in new code. See ZX-1467.
zx::unowned_resource resource(get_root_resource());
std::optional<ddk::MmioBuffer> buf;
zx_status_t status = ddk::MmioBuffer::Create(S905D3_HIU_BASE, S905D3_HIU_LENGTH, *resource,
ZX_CACHE_POLICY_UNCACHED_DEVICE, &buf);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: MmioBuffer::Create failed %d", __func__, status);
return status;
}
// SPICC1 clock enable @200MHz (fclk_div2(1GHz) / N(5)). For final SCLK frequency, see
// CONREG[16:18] in the SPI controller. This clock config produces a SCLK frequency of 50MHz
// assuming a default value for CONREG[16:18].
buf->Write32(spicc1_clk_sel_fclk_div2 | spicc1_clk_en | spicc1_clk_div(5), HHI_SPICC_CLK_CNTL);
}
zx_status_t status =
pbus_.CompositeDeviceAdd(&spi_dev, fragments, fbl::count_of(fragments), UINT32_MAX);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: DeviceAdd failed %d", __func__, status);
return status;
}
return ZX_OK;
}
} // namespace nelson