blob: fe6eb155c6929bf57176e876f053d9b04e052598 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Werner Zeh6c571462016-07-05 07:16:34 +02002
3#include <types.h>
Werner Zeh6c571462016-07-05 07:16:34 +02004#include <device/pci.h>
5#include <device/pci_ids.h>
6#include <device/pci_ops.h>
7#include <device/pci_def.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02008#include <device/mmio.h>
Werner Zeh6c571462016-07-05 07:16:34 +02009#include <hwilib.h>
Werner Zehf1f67c32017-10-19 07:21:54 +020010#include <bootstate.h>
Elyes HAOUASbf0970e2019-03-21 11:10:03 +010011
Werner Zeh6c571462016-07-05 07:16:34 +020012#include "nc_fpga.h"
13
Werner Zehf1f67c32017-10-19 07:21:54 +020014static void *nc_fpga_bar0;
15
Werner Zeh6c571462016-07-05 07:16:34 +020016#define FPGA_SET_PARAM(src, dst) \
17{ \
Werner Zeh2db79222017-07-05 15:52:52 +020018 uint32_t var; \
19 if (hwilib_get_field(src, (uint8_t *)&var, sizeof(var))) \
Werner Zehd5960c42017-07-14 10:24:00 +020020 dst = ((typeof(dst))var); \
Werner Zeh6c571462016-07-05 07:16:34 +020021}
22
23static void init_temp_mon (void *base_adr)
24{
25 uint32_t cc[5], i = 0;
26 uint8_t num = 0;
27 volatile fan_ctrl_t *ctrl = (fan_ctrl_t *)base_adr;
28
29 /* Program sensor delay first. */
30 FPGA_SET_PARAM(FANSensorDelay, ctrl->sensordelay);
31 /* Program correction curve for every used sensor. */
Werner Zeh2db79222017-07-05 15:52:52 +020032 if ((hwilib_get_field(FANSensorNum, &num, 1) != 1) ||
Werner Zeh6c571462016-07-05 07:16:34 +020033 (num == 0) || (num > MAX_NUM_SENSORS))
34 return;
35 for (i = 0; i < num; i ++) {
36 if (hwilib_get_field(FANSensorCfg0 + i, (uint8_t *)&cc[0],
37 sizeof(cc)) == sizeof(cc)) {
38 ctrl->sensorcfg[cc[0]].rmin = cc[1] & 0xffff;
39 ctrl->sensorcfg[cc[0]].rmax = cc[2] & 0xffff;
40 ctrl->sensorcfg[cc[0]].nmin = cc[3] & 0xffff;
41 ctrl->sensorcfg[cc[0]].nmax = cc[4] & 0xffff;
42 }
43 }
44 ctrl->sensornum = num;
Mario Scheithauer0b42c8a2017-09-26 13:37:49 +020045
46 /* Program sensor selection and temperature thresholds. */
47 FPGA_SET_PARAM(FANSensorSelect, ctrl->sensorselect);
48 FPGA_SET_PARAM(T_Warn, ctrl->t_warn);
49 FPGA_SET_PARAM(T_Crit, ctrl->t_crit);
Werner Zeh6c571462016-07-05 07:16:34 +020050}
51
52static void init_fan_ctrl (void *base_adr)
53{
Werner Zeh89a7b6b2017-06-30 10:38:08 +020054 uint8_t mask = 0, freeze_disable = 0, fan_req = 0;
Werner Zeh6c571462016-07-05 07:16:34 +020055 volatile fan_ctrl_t *ctrl = (fan_ctrl_t *)base_adr;
56
57 /* Program all needed fields of FAN controller. */
Werner Zeh6c571462016-07-05 07:16:34 +020058 FPGA_SET_PARAM(FANSamplingTime, ctrl->samplingtime);
59 FPGA_SET_PARAM(FANSetPoint, ctrl->setpoint);
60 FPGA_SET_PARAM(FANHystCtrl, ctrl->hystctrl);
61 FPGA_SET_PARAM(FANHystVal, ctrl->hystval);
62 FPGA_SET_PARAM(FANHystThreshold, ctrl->hystthreshold);
63 FPGA_SET_PARAM(FANKp, ctrl->kp);
64 FPGA_SET_PARAM(FANKi, ctrl->ki);
65 FPGA_SET_PARAM(FANKd, ctrl->kd);
66 FPGA_SET_PARAM(FANMaxSpeed, ctrl->fanmax);
Werner Zehc38ab852017-07-27 13:48:18 +020067 FPGA_SET_PARAM(FANStartSpeed, ctrl->fanmin);
Werner Zeh6c571462016-07-05 07:16:34 +020068 /* Set freeze and FAN configuration. */
69 if ((hwilib_get_field(FF_FanReq, &fan_req, 1) == 1) &&
Werner Zeh89a7b6b2017-06-30 10:38:08 +020070 (hwilib_get_field(FF_FreezeDis, &freeze_disable, 1) == 1)) {
Werner Zeh6c571462016-07-05 07:16:34 +020071 if (!fan_req)
72 mask = 1;
Elyes HAOUAS1943f372018-05-04 16:30:39 +020073 else if (fan_req && !freeze_disable)
Werner Zeh6c571462016-07-05 07:16:34 +020074 mask = 2;
75 else
76 mask = 3;
77 ctrl->fanmon = mask << 10;
78 }
79}
80
81/** \brief This function is the driver entry point for the init phase
82 * of the PCI bus allocator. It will initialize all the needed parts
83 * of NC_FPGA.
84 * @param *dev Pointer to the used PCI device
85 * @return void Nothing is given back
86 */
87static void nc_fpga_init(struct device *dev)
88{
89 void *bar0_ptr = NULL;
90 uint8_t cmd_reg;
91 uint32_t cap = 0;
92
93 /* All we need is mapped to BAR 0, get the address. */
94 bar0_ptr = (void *)(pci_read_config32(dev, PCI_BASE_ADDRESS_0) &
95 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK);
96 cmd_reg = pci_read_config8(dev, PCI_COMMAND);
97 /* Ensure BAR0 has a valid value. */
98 if (!bar0_ptr || !(cmd_reg & PCI_COMMAND_MEMORY))
99 return;
100 /* Ensure this is really a NC FPGA by checking magic register. */
101 if (read32(bar0_ptr + NC_MAGIC_OFFSET) != NC_FPGA_MAGIC)
102 return;
Werner Zehf1f67c32017-10-19 07:21:54 +0200103 /* Save BAR0 address so that it can be used on all NC_FPGA devices to
104 set the FW_DONE bit before jumping to payload. */
105 nc_fpga_bar0 = bar0_ptr;
Werner Zeh6c571462016-07-05 07:16:34 +0200106 /* Open hwinfo block. */
107 if (hwilib_find_blocks("hwinfo.hex") != CB_SUCCESS)
108 return;
109 /* Set up FAN controller and temperature monitor according to */
110 /* capability bits. */
111 cap = read32(bar0_ptr + NC_CAP1_OFFSET);
112 if (cap & (NC_CAP1_TEMP_MON | NC_CAP1_FAN_CTRL))
113 init_temp_mon(bar0_ptr + NC_FANMON_CTRL_OFFSET);
114 if (cap & NC_CAP1_FAN_CTRL)
115 init_fan_ctrl(bar0_ptr + NC_FANMON_CTRL_OFFSET);
Mario Scheithauerc4ff1de2017-06-12 10:02:10 +0200116 if (cap & NC_CAP1_DSAVE_NMI_DELAY) {
117 uint16_t *dsave_ptr = (uint16_t *)(bar0_ptr + NC_DSAVE_OFFSET);
118 FPGA_SET_PARAM(NvramVirtTimeDsaveReset, *dsave_ptr);
119 }
120 if (cap & NC_CAP1_BL_BRIGHTNESS_CTRL) {
121 uint8_t *bl_bn_ptr =
122 (uint8_t *)(bar0_ptr + NC_BL_BRIGHTNESS_OFFSET);
123 uint8_t *bl_pwm_ptr = (uint8_t *)(bar0_ptr + NC_BL_PWM_OFFSET);
124 FPGA_SET_PARAM(BL_Brightness, *bl_bn_ptr);
125 FPGA_SET_PARAM(PF_PwmFreq, *bl_pwm_ptr);
126 }
Werner Zeh6c571462016-07-05 07:16:34 +0200127}
128
Julius Wernercd49cce2019-03-05 16:53:33 -0800129#if CONFIG(NC_FPGA_NOTIFY_CB_READY)
Werner Zehf1f67c32017-10-19 07:21:54 +0200130/* Set FW_DONE bit in FPGA before jumping to payload. */
131static void set_fw_done(void *unused)
132{
133 uint32_t reg;
134
135 if (nc_fpga_bar0) {
136 reg = read32(nc_fpga_bar0 + NC_DIAG_CTRL_OFFSET);
137 reg |= NC_DIAG_FW_DONE;
138 write32(nc_fpga_bar0 + NC_DIAG_CTRL_OFFSET, reg);
139 }
140}
141
142BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, set_fw_done, NULL);
143#endif
144
Werner Zeh42b88352021-11-16 07:31:44 +0100145static void nc_fpga_set_resources(struct device *dev)
146{
147 pci_dev_set_resources(dev);
148
149 if (CONFIG(NC_FPGA_POST_CODE)) {
150 /* Re-initialize base address after set_resources for POST display
151 to work properly.*/
152 nc_fpga_remap(pci_read_config32(dev, PCI_BASE_ADDRESS_0) & ~0xf);
153 }
154}
155
156
Werner Zeh6c571462016-07-05 07:16:34 +0200157static struct device_operations nc_fpga_ops = {
158 .read_resources = pci_dev_read_resources,
Werner Zeh42b88352021-11-16 07:31:44 +0100159 .set_resources = nc_fpga_set_resources,
Werner Zeh6c571462016-07-05 07:16:34 +0200160 .enable_resources = pci_dev_enable_resources,
161 .init = nc_fpga_init,
Werner Zeh6c571462016-07-05 07:16:34 +0200162};
163
Mario Scheithauerc4ff1de2017-06-12 10:02:10 +0200164static const unsigned short nc_fpga_device_ids[] = { 0x4080, 0x4091, 0 };
Werner Zeh6c571462016-07-05 07:16:34 +0200165
166static const struct pci_driver nc_fpga_driver __pci_driver = {
167 .ops = &nc_fpga_ops,
Felix Singer43b7f412022-03-07 04:34:52 +0100168 .vendor = PCI_VID_SIEMENS,
Werner Zeh6c571462016-07-05 07:16:34 +0200169 .devices = nc_fpga_device_ids,
170};