blob: ea5d0bcdf51f0b3d83356ee3961a7eb67674ddbc [file] [log] [blame]
Wan Yee Lau3f190c52024-02-05 11:47:16 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2024 Intel Corporation <www.intel.com>
4 */
5
6#include <dm.h>
7#include <errno.h>
8#include <asm/io.h>
9#include <linux/sizes.h>
10
11#define NUMBER_OF_ELEMENTS 3
12
13static int socfpga_dtreg_probe(struct udevice *dev)
14{
15 const fdt32_t *list;
16 fdt_addr_t offset, base;
17 fdt_val_t val, read_val, mask, set_mask;
18 int size, i;
19 u32 blk_sz, reg;
20 ofnode node;
21 const char *name = NULL;
22
23 debug("%s(dev=%p)\n", __func__, dev);
24
25 if (!dev_has_ofnode(dev))
26 return 0;
27
28 dev_for_each_subnode(node, dev) {
29 name = ofnode_get_name(node);
30 if (!name)
31 return -EINVAL;
32
33 if (ofnode_read_u32_index(node, "reg", 1, &blk_sz))
34 return -EINVAL;
35
36 base = ofnode_get_addr(node);
37 if (base == FDT_ADDR_T_NONE)
38 return -EINVAL;
39
40 debug("%s(node_offset 0x%lx node_name %s ", __func__,
41 node.of_offset, name);
42 debug("node addr 0x%llx blk sz 0x%x)\n", base, blk_sz);
43
44 list = ofnode_read_prop(node, "intel,offset-settings", &size);
45 if (!list)
46 return -EINVAL;
47
48 debug("%s(intel,offset-settings property size=%x)\n", __func__,
49 size);
50 size /= sizeof(*list) * NUMBER_OF_ELEMENTS;
51
52 /*
53 * First element: offset
54 * Second element: val
55 * Third element: mask
56 */
57 for (i = 0; i < size; i++) {
58 offset = fdt32_to_cpu(*list++);
59 val = fdt32_to_cpu(*list++);
60
61 /* Reads the masking bit value from the list */
62 mask = fdt32_to_cpu(*list++);
63
64 /*
65 * Reads out the offsets, value and masking bits
66 * Ex: <0x00000000 0x00000230 0xffffffff>
67 */
68 debug("%s(intel,offset-settings 0x%llx : 0x%llx : 0x%llx)\n",
69 __func__, offset, val, mask);
70
71 if (blk_sz < offset + SZ_4) {
72 printf("%s: Overflow as offset 0x%llx or reg",
73 __func__, offset);
74 printf(" write is more than block size 0x%x\n",
75 blk_sz);
76 return -EINVAL;
77 }
78
79 if (mask != 0) {
80 if (mask == 0xffffffff) {
81 reg = base + offset;
82 writel(val, (uintptr_t)reg);
83 } else {
84 /* Mask the value with the masking bits */
85 set_mask = val & mask;
86
87 reg = base + offset;
88
89 /* Clears and sets specific bits in the register */
90 clrsetbits_le32((uintptr_t)reg, mask, set_mask);
91 }
92 }
93
94 read_val = readl((uintptr_t)reg);
95
96 /* Reads out the register, masked value and the read value */
97 debug("%s(reg 0x%x = wr : 0x%llx rd : 0x%llx)\n",
98 __func__, reg, set_mask, read_val);
99 }
100 }
101
102 return 0;
103};
104
105static const struct udevice_id socfpga_dtreg_ids[] = {
106 {.compatible = "intel,socfpga-dtreg"},
107 { }
108};
109
110U_BOOT_DRIVER(socfpga_dtreg) = {
111 .name = "socfpga-dtreg",
112 .id = UCLASS_NOP,
113 .of_match = socfpga_dtreg_ids,
114 .probe = socfpga_dtreg_probe,
115};