blob: ebc2d9ca489cb29151c8fadc691b18971287f253 [file] [log] [blame]
Patrick Rudolph5e9dc372017-11-19 09:11:58 +01001/*
2 * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com>
3 * Copyright (C) 2017 Patrick Rudolph <siro@das-labor.org>
4 *
Damien Zammitf0a91282019-02-23 12:38:15 +11005 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
Patrick Rudolph5e9dc372017-11-19 09:11:58 +01009 *
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 <stdio.h>
17#include <inttypes.h>
18
19#include "intelmetool.h"
20#include "mmap.h"
21#include "rcba.h"
22
23static const int size = 0x4000;
24
25/* Returns the physical RCBA base address or zero on error. */
Patrick Rudolph0391d0b2018-02-01 16:14:19 +010026u32 get_rcba_phys(void)
Patrick Rudolph5e9dc372017-11-19 09:11:58 +010027{
28 struct pci_access *pacc;
29 struct pci_dev *sb;
30 uint32_t rcba_phys;
31
32 pacc = pci_alloc();
33 pacc->method = PCI_ACCESS_I386_TYPE1;
34
35 pci_init(pacc);
36 pci_scan_bus(pacc);
37
38 sb = pci_get_dev(pacc, 0, 0, 0x1f, 0);
39 if (!sb) {
40 printf("Uh oh, southbridge not on BDF(0:31:0), please report "
41 "this error, exiting.\n");
42 pci_cleanup(pacc);
43 return 0;
44 }
45 pci_fill_info(sb, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_SIZES |
46 PCI_FILL_CLASS);
47
48 rcba_phys = pci_read_long(sb, 0xf0) & 0xfffffffe;
49
50 pci_free_dev(sb);
51 pci_cleanup(pacc);
52
53 return rcba_phys;
54}
55
56/*
57 * Writes 'val' to RCBA register at address 'addr'.
58 * Returns 1 on error and 0 on success.
59 */
60int write_rcba32(uint32_t addr, uint32_t val)
61{
62 volatile uint8_t *rcba;
63 const uint32_t rcba_phys = get_rcba_phys();
64
65 if (!rcba_phys) {
66 printf("Could not get RCBA address\n");
67 return 1;
68 }
69
70 rcba = map_physical((off_t)rcba_phys, size);
71 if (rcba == NULL) {
Patrick Rudolphad4ddfc2018-02-02 15:07:09 +010072 printf("Could not map RCBA\n"
Jonathan Neuschäfer5be7bb32018-04-17 13:06:49 +020073 "Do you have kernel cmdline argument 'iomem=relaxed' set ?\n");
Patrick Rudolph5e9dc372017-11-19 09:11:58 +010074 return 1;
75 }
76 *(uint32_t *)(rcba + addr) = val;
77
78 munmap((void *)rcba, size);
79 return 0;
80}
81
82/*
83 * Reads RCBA register at address 'addr' and stores it in 'val'.
84 * Returns 1 on error and 0 on success.
85 */
86int read_rcba32(uint32_t addr, uint32_t *val)
87{
88 volatile uint8_t *rcba;
89 const uint32_t rcba_phys = get_rcba_phys();
90
91 if (!rcba_phys) {
92 printf("Could not get RCBA address\n");
93 return 1;
94 }
95
96 rcba = map_physical((off_t)rcba_phys, size);
97 if (rcba == NULL) {
Patrick Rudolphad4ddfc2018-02-02 15:07:09 +010098 printf("Could not map RCBA\n"
Jonathan Neuschäfer5be7bb32018-04-17 13:06:49 +020099 "Do you have kernel cmdline argument 'iomem=relaxed' set ?\n");
Patrick Rudolph5e9dc372017-11-19 09:11:58 +0100100 return 1;
101 }
102
103 *val = *(uint32_t *)(rcba + addr);
104
105 munmap((void *)rcba, size);
106 return 0;
107}