1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <ddk/debug.h>
6#include <ddk/device.h>
7#include <ddk/io-buffer.h>
8#include <ddk/metadata.h>
9#include <ddk/metadata/nand.h>
10#include <ddk/protocol/gpio.h>
11#include <ddk/protocol/platform-bus.h>
12#include <ddk/protocol/platform-defs.h>
13#include <hw/reg.h>
14#include <soc/aml-s905d2/s905d2-hw.h>
15#include <soc/aml-s905d2/s905d2-gpio.h>
16#include <unistd.h>
17#include <zircon/hw/gpt.h>
18
19#include "astro.h"
20
21static const pbus_mmio_t raw_nand_mmios[] = {
22    {   /* nandreg : Registers for NAND controller */
23        .base = S905D2_RAW_NAND_REG_BASE,
24        .length = 0x2000,
25    },
26    {   /* clockreg : Clock Register for NAND controller */
27        .base = S905D2_RAW_NAND_CLOCK_BASE,
28        .length = 0x4,  /* Just 4 bytes */
29    },
30};
31
32static const pbus_irq_t raw_nand_irqs[] = {
33    {
34        .irq = S905D2_RAW_NAND_IRQ,
35    },
36};
37
38static const pbus_bti_t raw_nand_btis[] = {
39    {
40        .iommu_index = 0,
41        .bti_id = BTI_AML_RAW_NAND,
42    },
43};
44
45static const nand_config_t config = {
46    .bad_block_config = {
47        .type = kAmlogicUboot,
48        .aml = {
49            .table_start_block = 20,
50            .table_end_block = 23,
51        },
52    },
53    .extra_partition_config_count = 1,
54    .extra_partition_config = {
55        {
56            .type_guid = GUID_BOOTLOADER_VALUE,
57            .copy_count = 4,
58        },
59    },
60};
61
62static const pbus_metadata_t raw_nand_metadata[] = {
63    {
64        .type = DEVICE_METADATA_PRIVATE,
65        .data = &config,
66        .len = sizeof(config),
67    },
68};
69
70static const pbus_boot_metadata_t raw_nand_boot_metadata[] = {
71    {
72        .zbi_type = DEVICE_METADATA_PARTITION_MAP,
73        .zbi_extra = 0,
74    },
75};
76
77static const pbus_dev_t raw_nand_dev = {
78    .name = "aml_raw_nand",
79    .vid = PDEV_VID_AMLOGIC,
80    .pid = PDEV_PID_GENERIC,
81    .did = PDEV_DID_AMLOGIC_RAW_NAND,
82    .mmios = raw_nand_mmios,
83    .mmio_count = countof(raw_nand_mmios),
84    .irqs = raw_nand_irqs,
85    .irq_count = countof(raw_nand_irqs),
86    .btis = raw_nand_btis,
87    .bti_count = countof(raw_nand_btis),
88    .metadata = raw_nand_metadata,
89    .metadata_count = countof(raw_nand_metadata),
90    .boot_metadata = raw_nand_boot_metadata,
91    .boot_metadata_count = countof(raw_nand_boot_metadata),
92};
93
94zx_status_t aml_raw_nand_init(aml_bus_t* bus) {
95    zx_status_t status;
96
97    // Set alternate functions to enable raw_nand.
98    status = gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOBOOT(8), 2);
99    if (status != ZX_OK)
100        return status;
101    status = gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOBOOT(9), 2);
102    if (status != ZX_OK)
103        return status;
104    status = gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOBOOT(10), 2);
105    if (status != ZX_OK)
106        return status;
107    status = gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOBOOT(11), 2);
108    if (status != ZX_OK)
109        return status;
110    status = gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOBOOT(12), 2);
111    if (status != ZX_OK)
112        return status;
113    status = gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOBOOT(14), 2);
114    if (status != ZX_OK)
115        return status;
116    status = gpio_impl_set_alt_function(&bus->gpio, S905D2_GPIOBOOT(15), 2);
117    if (status != ZX_OK)
118        return status;
119
120    status = pbus_device_add(&bus->pbus, &raw_nand_dev);
121    if (status != ZX_OK) {
122        zxlogf(ERROR, "%s: pbus_device_add failed: %d\n",
123               __func__, status);
124        return status;
125    }
126
127    return ZX_OK;
128}
129
130