blob: 59e7d4bd2fcf562fd95b858e09c4616f62e1d951 [file] [log] [blame]
Werner Zeh6c571462016-07-05 07:16:34 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2016 Siemens AG.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <types.h>
17#include <console/console.h>
18#include <device/pci.h>
19#include <device/pci_ids.h>
20#include <device/pci_ops.h>
21#include <device/pci_def.h>
22#include <string.h>
23#include <delay.h>
24#include <hwilib.h>
25#include "nc_fpga.h"
26
27#define FPGA_SET_PARAM(src, dst) \
28{ \
29 typeof(dst) var; \
30 size_t len = sizeof(var); \
31 if (hwilib_get_field(src, (uint8_t *)&var, len) == len) \
32 dst = (typeof(dst))(var); \
33}
34
35static void init_temp_mon (void *base_adr)
36{
37 uint32_t cc[5], i = 0;
38 uint8_t num = 0;
39 volatile fan_ctrl_t *ctrl = (fan_ctrl_t *)base_adr;
40
41 /* Program sensor delay first. */
42 FPGA_SET_PARAM(FANSensorDelay, ctrl->sensordelay);
43 /* Program correction curve for every used sensor. */
44 if (hwilib_get_field(FANSensorNum, &num, sizeof(num) != sizeof(num)) ||
45 (num == 0) || (num > MAX_NUM_SENSORS))
46 return;
47 for (i = 0; i < num; i ++) {
48 if (hwilib_get_field(FANSensorCfg0 + i, (uint8_t *)&cc[0],
49 sizeof(cc)) == sizeof(cc)) {
50 ctrl->sensorcfg[cc[0]].rmin = cc[1] & 0xffff;
51 ctrl->sensorcfg[cc[0]].rmax = cc[2] & 0xffff;
52 ctrl->sensorcfg[cc[0]].nmin = cc[3] & 0xffff;
53 ctrl->sensorcfg[cc[0]].nmax = cc[4] & 0xffff;
54 }
55 }
56 ctrl->sensornum = num;
57}
58
59static void init_fan_ctrl (void *base_adr)
60{
61 uint8_t mask = 0, freeze_mode = 0, fan_req = 0;
62 volatile fan_ctrl_t *ctrl = (fan_ctrl_t *)base_adr;
63
64 /* Program all needed fields of FAN controller. */
65 FPGA_SET_PARAM(FANSensorSelect, ctrl->sensorselect);
66 FPGA_SET_PARAM(T_Warn, ctrl->t_warn);
67 FPGA_SET_PARAM(T_Crit, ctrl->t_crit);
68 FPGA_SET_PARAM(FANSamplingTime, ctrl->samplingtime);
69 FPGA_SET_PARAM(FANSetPoint, ctrl->setpoint);
70 FPGA_SET_PARAM(FANHystCtrl, ctrl->hystctrl);
71 FPGA_SET_PARAM(FANHystVal, ctrl->hystval);
72 FPGA_SET_PARAM(FANHystThreshold, ctrl->hystthreshold);
73 FPGA_SET_PARAM(FANKp, ctrl->kp);
74 FPGA_SET_PARAM(FANKi, ctrl->ki);
75 FPGA_SET_PARAM(FANKd, ctrl->kd);
76 FPGA_SET_PARAM(FANMaxSpeed, ctrl->fanmax);
77 /* Set freeze and FAN configuration. */
78 if ((hwilib_get_field(FF_FanReq, &fan_req, 1) == 1) &&
79 (hwilib_get_field(FF_FreezeDis, &freeze_mode, 1) == 1)) {
80 if (!fan_req)
81 mask = 1;
82 else if (fan_req && freeze_mode)
83 mask = 2;
84 else
85 mask = 3;
86 ctrl->fanmon = mask << 10;
87 }
88}
89
90/** \brief This function is the driver entry point for the init phase
91 * of the PCI bus allocator. It will initialize all the needed parts
92 * of NC_FPGA.
93 * @param *dev Pointer to the used PCI device
94 * @return void Nothing is given back
95 */
96static void nc_fpga_init(struct device *dev)
97{
98 void *bar0_ptr = NULL;
99 uint8_t cmd_reg;
100 uint32_t cap = 0;
101
102 /* All we need is mapped to BAR 0, get the address. */
103 bar0_ptr = (void *)(pci_read_config32(dev, PCI_BASE_ADDRESS_0) &
104 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK);
105 cmd_reg = pci_read_config8(dev, PCI_COMMAND);
106 /* Ensure BAR0 has a valid value. */
107 if (!bar0_ptr || !(cmd_reg & PCI_COMMAND_MEMORY))
108 return;
109 /* Ensure this is really a NC FPGA by checking magic register. */
110 if (read32(bar0_ptr + NC_MAGIC_OFFSET) != NC_FPGA_MAGIC)
111 return;
112 /* Open hwinfo block. */
113 if (hwilib_find_blocks("hwinfo.hex") != CB_SUCCESS)
114 return;
115 /* Set up FAN controller and temperature monitor according to */
116 /* capability bits. */
117 cap = read32(bar0_ptr + NC_CAP1_OFFSET);
118 if (cap & (NC_CAP1_TEMP_MON | NC_CAP1_FAN_CTRL))
119 init_temp_mon(bar0_ptr + NC_FANMON_CTRL_OFFSET);
120 if (cap & NC_CAP1_FAN_CTRL)
121 init_fan_ctrl(bar0_ptr + NC_FANMON_CTRL_OFFSET);
Mario Scheithauerc4ff1de2017-06-12 10:02:10 +0200122 if (cap & NC_CAP1_DSAVE_NMI_DELAY) {
123 uint16_t *dsave_ptr = (uint16_t *)(bar0_ptr + NC_DSAVE_OFFSET);
124 FPGA_SET_PARAM(NvramVirtTimeDsaveReset, *dsave_ptr);
125 }
126 if (cap & NC_CAP1_BL_BRIGHTNESS_CTRL) {
127 uint8_t *bl_bn_ptr =
128 (uint8_t *)(bar0_ptr + NC_BL_BRIGHTNESS_OFFSET);
129 uint8_t *bl_pwm_ptr = (uint8_t *)(bar0_ptr + NC_BL_PWM_OFFSET);
130 FPGA_SET_PARAM(BL_Brightness, *bl_bn_ptr);
131 FPGA_SET_PARAM(PF_PwmFreq, *bl_pwm_ptr);
132 }
Werner Zeh6c571462016-07-05 07:16:34 +0200133}
134
135static struct device_operations nc_fpga_ops = {
136 .read_resources = pci_dev_read_resources,
137 .set_resources = pci_dev_set_resources,
138 .enable_resources = pci_dev_enable_resources,
139 .init = nc_fpga_init,
140 .scan_bus = 0,
141 .ops_pci = 0,
142};
143
Mario Scheithauerc4ff1de2017-06-12 10:02:10 +0200144static const unsigned short nc_fpga_device_ids[] = { 0x4080, 0x4091, 0 };
Werner Zeh6c571462016-07-05 07:16:34 +0200145
146static const struct pci_driver nc_fpga_driver __pci_driver = {
147 .ops = &nc_fpga_ops,
Mario Scheithauerc4ff1de2017-06-12 10:02:10 +0200148 .vendor = PCI_VENDOR_ID_SIEMENS,
Werner Zeh6c571462016-07-05 07:16:34 +0200149 .devices = nc_fpga_device_ids,
150};