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-a113/a113-hw.h>
15#include <unistd.h>
16#include <zircon/hw/gpt.h>
17
18#include "gauss.h"
19#include "gauss-hw.h"
20
21static const pbus_mmio_t raw_nand_mmios[] = {
22    {   /* nandreg : Registers for NAND controller */
23        .base = GAUSS_RAW_NAND_REG,
24        .length = 0x2000,
25    },
26    {   /* clockreg : Clock Register for NAND controller */
27        /*
28         * From the Linux devicetree. This is the base SD_EMMC_CLOCK
29         * register (for port C)
30         */
31        .base = GAUSS_RAW_NAND_CLKREG,
32        .length = 0x4,  /* Just 4 bytes */
33    },
34};
35
36static const pbus_irq_t raw_nand_irqs[] = {
37    {
38        .irq = GAUSS_RAW_NAND_IRQ,
39    },
40};
41
42static const pbus_bti_t raw_nand_btis[] = {
43    {
44        .iommu_index = 0,
45        .bti_id = BTI_AML_RAW_NAND,
46    },
47};
48
49static const nand_config_t config = {
50    .bad_block_config = {
51        .type = kAmlogicUboot,
52        .aml = {
53            .table_start_block = 20,
54            .table_end_block = 23,
55        },
56    },
57    .extra_partition_config_count = 1,
58    .extra_partition_config = {
59        {
60            .type_guid = GUID_BOOTLOADER_VALUE,
61            .copy_count = 4,
62        },
63    },
64};
65
66static const pbus_metadata_t raw_nand_metadata[] = {
67    {
68        .type = DEVICE_METADATA_PRIVATE,
69        .data = &config,
70        .len = sizeof(config),
71    },
72};
73
74static const pbus_boot_metadata_t raw_nand_boot_metadata[] = {
75    {
76        .zbi_type = DEVICE_METADATA_PARTITION_MAP,
77        .zbi_extra = 0,
78    },
79};
80
81static const pbus_dev_t raw_nand_dev = {
82    .name = "aml_raw_nand",
83    .vid = PDEV_VID_AMLOGIC,
84    .pid = PDEV_PID_GENERIC,
85    .did = PDEV_DID_AMLOGIC_RAW_NAND,
86    .mmios = raw_nand_mmios,
87    .mmio_count = countof(raw_nand_mmios),
88    .irqs = raw_nand_irqs,
89    .irq_count = countof(raw_nand_irqs),
90    .btis = raw_nand_btis,
91    .bti_count = countof(raw_nand_btis),
92    .metadata = raw_nand_metadata,
93    .metadata_count = countof(raw_nand_metadata),
94    .boot_metadata = raw_nand_boot_metadata,
95    .boot_metadata_count = countof(raw_nand_boot_metadata),
96};
97
98zx_status_t gauss_raw_nand_init(gauss_bus_t* bus) {
99    zx_status_t status;
100
101    // set alternate functions to enable raw_nand
102    status = gpio_impl_set_alt_function(&bus->gpio, A113_GPIOBOOT(8), 2);
103    if (status != ZX_OK)
104        return status;
105    status = gpio_impl_set_alt_function(&bus->gpio, A113_GPIOBOOT(9), 2);
106    if (status != ZX_OK)
107        return status;
108    status = gpio_impl_set_alt_function(&bus->gpio, A113_GPIOBOOT(10), 2);
109    if (status != ZX_OK)
110        return status;
111    status = gpio_impl_set_alt_function(&bus->gpio, A113_GPIOBOOT(11), 2);
112    if (status != ZX_OK)
113        return status;
114    status = gpio_impl_set_alt_function(&bus->gpio, A113_GPIOBOOT(12), 2);
115    if (status != ZX_OK)
116        return status;
117    status = gpio_impl_set_alt_function(&bus->gpio, A113_GPIOBOOT(13), 2);
118    if (status != ZX_OK)
119        return status;
120
121    status = pbus_device_add(&bus->pbus, &raw_nand_dev);
122    if (status != ZX_OK) {
123        zxlogf(ERROR, "gauss_raw_nand_init: pbus_device_add raw_nand failed: %d\n",
124               status);
125        return status;
126    }
127
128    return ZX_OK;
129}
130
131