├── .gitignore ├── Makefile ├── README.md ├── asic ├── asic-navi.c ├── asic-polaris.c ├── asic-registers.h ├── asic-types.h └── asic-vega.c ├── atom ├── atom-bits.h ├── atom-names.h ├── atom.c ├── atom.h ├── parser.c └── types.h ├── aura-gpu-bios.c ├── aura-gpu-bios.h ├── aura-gpu-hw.c ├── aura-gpu-hw.h ├── aura-gpu-i2c.c ├── aura-gpu-i2c.h ├── aura-gpu-reg.c ├── aura-gpu-reg.h ├── debug.h ├── include ├── debug.h ├── err.h ├── quirks.h └── types.h ├── main.c └── pci_ids.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *~ 3 | *.d 4 | *core 5 | *.depend 6 | *.*.cmd 7 | *.mod 8 | *.mod.c 9 | *.tmp_versions 10 | *.order 11 | *.symvers 12 | build 13 | 14 | aura/usb 15 | aura/err.h 16 | *dump 17 | drivers/Makefile 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CONFIG_MODULE_SIG=n 2 | CONFIG_STACK_VALIDATION=n 3 | MODULE_NAME = aura-gpu 4 | 5 | SRCS = \ 6 | asic/asic-polaris.c \ 7 | asic/asic-vega.c \ 8 | asic/asic-navi.c \ 9 | atom/atom.c \ 10 | aura-gpu-reg.c \ 11 | aura-gpu-i2c.c \ 12 | aura-gpu-bios.c \ 13 | aura-gpu-hw.c \ 14 | main.c 15 | 16 | KERNELDIR = /lib/modules/$(shell uname -r)/build 17 | PWD = $(shell pwd) 18 | KBUILD_EXTRA_SYMBOLS := $(ADAPTERDIR)/Module.symvers 19 | OBJS = $(SRCS:.c=.o) 20 | 21 | ifeq ($(KERNELRELEASE),) 22 | 23 | all: 24 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules EXTRA_CFLAGS="-g -DDEBUG -I$(PWD)/../" 25 | 26 | clean: 27 | $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 28 | 29 | uninstall: 30 | sudo rmmod $(MODULE_NAME) || true 31 | 32 | install: uninstall all 33 | sudo insmod $(MODULE_NAME).ko 34 | 35 | .PHONY: all clean uninstall install 36 | 37 | else 38 | 39 | obj-m += $(MODULE_NAME).o 40 | $(MODULE_NAME)-y = $(OBJS) 41 | 42 | endif 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Before Installing 2 | ================= 3 | 4 | You are required to have `gcc`, `make` and `kernel-headers` installed for building the module. 5 | 6 | To detect your kernel version run: 7 | ``` 8 | uname -r 9 | ``` 10 | It will output something like 11 | ``` 12 | 5.3.11-1-MANJARO 13 | ``` 14 | Then, on Manjaro, run: 15 | ``` 16 | sudo pacman -S linux53-headers 17 | ``` 18 | 19 | To Install 20 | ========== 21 | Clone the repo into a github directory in your home folder: 22 | ``` 23 | mkdir github 24 | cd github 25 | git clone https://github.com/twifty/aura-gpu.git 26 | cd aura-gpu 27 | ``` 28 | Then run: 29 | ``` 30 | make install 31 | ``` 32 | The installer will prompt for your sudo password in order to insert the module into the kernel. 33 | 34 | After Install 35 | ============= 36 | The `i2c-dev` module is required: 37 | ``` 38 | sudo pacman -S i2c-tools 39 | sudo modprobe i2c-dev 40 | ``` 41 | List all i2c devices with: 42 | ``` 43 | sudo i2cdetect -l 44 | ``` 45 | It will output something like 46 | ``` 47 | i2c-3 smbus SMBus PIIX4 adapter port 4 at 0b00 SMBus adapter 48 | i2c-10 i2c AMDGPU DM i2c hw bus 4 I2C adapter 49 | i2c-1 smbus SMBus PIIX4 adapter port 2 at 0b00 SMBus adapter 50 | i2c-8 i2c AMDGPU DM i2c hw bus 2 I2C adapter 51 | i2c-6 i2c AMDGPU DM i2c hw bus 1 I2C adapter 52 | i2c-4 i2c AMDGPU DM i2c hw bus 0 I2C adapter 53 | i2c-11 i2c AURA GPU adapter I2C adapter 54 | i2c-2 smbus SMBus PIIX4 adapter port 3 at 0b00 SMBus adapter 55 | i2c-0 smbus SMBus PIIX4 adapter port 0 at 0b00 SMBus adapter 56 | i2c-9 i2c AMDGPU DM i2c hw bus 3 I2C adapter 57 | i2c-7 i2c dmdc I2C adapter 58 | i2c-5 i2c dmdc I2C adapter 59 | ``` 60 | Here we can see this module "AURA GPU adapter" is detected as device number 11. We can now scan that device with: 61 | ``` 62 | sudo i2cdetect -y 11 63 | ``` 64 | It should output all clients available on that bus: 65 | ``` 66 | 0 1 2 3 4 5 6 7 8 9 a b c d e f 67 | 00: -- -- -- -- -- 08 -- -- -- -- -- -- -- 68 | 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 69 | 20: -- -- -- -- -- -- -- -- -- 29 -- -- -- -- -- -- 70 | 30: 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 71 | 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 72 | 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 73 | 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 74 | 70: 70 -- -- -- -- -- -- -- 75 | ``` 76 | -------------------------------------------------------------------------------- /asic/asic-navi.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | #include "asic-registers.h" 3 | 4 | #define mmGENERIC_I2C_CONTROL 0x1eb8 5 | #define mmGENERIC_I2C_INTERRUPT_CONTROL 0x1eb9 6 | #define mmGENERIC_I2C_STATUS 0x1eba 7 | #define mmGENERIC_I2C_SPEED 0x1ebb 8 | #define mmGENERIC_I2C_SETUP 0x1ebc 9 | #define mmGENERIC_I2C_TRANSACTION 0x1ebd 10 | #define mmGENERIC_I2C_DATA 0x1ebe 11 | #define mmGENERIC_I2C_PIN_SELECTION 0x1ebf 12 | 13 | //GENERIC_I2C_CONTROL 14 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_GO__SHIFT 0x0 15 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SOFT_RESET__SHIFT 0x1 16 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SEND_RESET__SHIFT 0x2 17 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_ENABLE__SHIFT 0x3 18 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_GO_MASK 0x00000001L 19 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SOFT_RESET_MASK 0x00000002L 20 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SEND_RESET_MASK 0x00000004L 21 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_ENABLE_MASK 0x00000008L 22 | //GENERIC_I2C_INTERRUPT_CONTROL 23 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_INT__SHIFT 0x0 24 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_ACK__SHIFT 0x1 25 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_MASK__SHIFT 0x2 26 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_INT_MASK 0x00000001L 27 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_ACK_MASK 0x00000002L 28 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_MASK_MASK 0x00000004L 29 | //GENERIC_I2C_STATUS 30 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STATUS__SHIFT 0x0 31 | #define GENERIC_I2C_STATUS__GENERIC_I2C_DONE__SHIFT 0x4 32 | #define GENERIC_I2C_STATUS__GENERIC_I2C_ABORTED__SHIFT 0x5 33 | #define GENERIC_I2C_STATUS__GENERIC_I2C_TIMEOUT__SHIFT 0x6 34 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STOPPED_ON_NACK__SHIFT 0x9 35 | #define GENERIC_I2C_STATUS__GENERIC_I2C_NACK__SHIFT 0xa 36 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STATUS_MASK 0x0000000FL 37 | #define GENERIC_I2C_STATUS__GENERIC_I2C_DONE_MASK 0x00000010L 38 | #define GENERIC_I2C_STATUS__GENERIC_I2C_ABORTED_MASK 0x00000020L 39 | #define GENERIC_I2C_STATUS__GENERIC_I2C_TIMEOUT_MASK 0x00000040L 40 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STOPPED_ON_NACK_MASK 0x00000200L 41 | #define GENERIC_I2C_STATUS__GENERIC_I2C_NACK_MASK 0x00000400L 42 | //GENERIC_I2C_SPEED 43 | #define GENERIC_I2C_SPEED__GENERIC_I2C_THRESHOLD__SHIFT 0x0 44 | #define GENERIC_I2C_SPEED__GENERIC_I2C_DISABLE_FILTER_DURING_STALL__SHIFT 0x4 45 | #define GENERIC_I2C_SPEED__GENERIC_I2C_START_STOP_TIMING_CNTL__SHIFT 0x8 46 | #define GENERIC_I2C_SPEED__GENERIC_I2C_PRESCALE__SHIFT 0x10 47 | #define GENERIC_I2C_SPEED__GENERIC_I2C_THRESHOLD_MASK 0x00000003L 48 | #define GENERIC_I2C_SPEED__GENERIC_I2C_DISABLE_FILTER_DURING_STALL_MASK 0x00000010L 49 | #define GENERIC_I2C_SPEED__GENERIC_I2C_START_STOP_TIMING_CNTL_MASK 0x00000300L 50 | #define GENERIC_I2C_SPEED__GENERIC_I2C_PRESCALE_MASK 0xFFFF0000L 51 | //GENERIC_I2C_SETUP 52 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_EN__SHIFT 0x0 53 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_SEL__SHIFT 0x1 54 | #define GENERIC_I2C_SETUP__GENERIC_I2C_CLK_DRIVE_EN__SHIFT 0x7 55 | #define GENERIC_I2C_SETUP__GENERIC_I2C_INTRA_BYTE_DELAY__SHIFT 0x8 56 | #define GENERIC_I2C_SETUP__GENERIC_I2C_TIME_LIMIT__SHIFT 0x18 57 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_EN_MASK 0x00000001L 58 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_SEL_MASK 0x00000002L 59 | #define GENERIC_I2C_SETUP__GENERIC_I2C_CLK_DRIVE_EN_MASK 0x00000080L 60 | #define GENERIC_I2C_SETUP__GENERIC_I2C_INTRA_BYTE_DELAY_MASK 0x0000FF00L 61 | #define GENERIC_I2C_SETUP__GENERIC_I2C_TIME_LIMIT_MASK 0xFF000000L 62 | //GENERIC_I2C_TRANSACTION 63 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_RW__SHIFT 0x0 64 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_ON_NACK__SHIFT 0x8 65 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_ACK_ON_READ__SHIFT 0x9 66 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_START__SHIFT 0xc 67 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP__SHIFT 0xd 68 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_COUNT__SHIFT 0x10 69 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_RW_MASK 0x00000001L 70 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_ON_NACK_MASK 0x00000100L 71 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_ACK_ON_READ_MASK 0x00000200L 72 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_START_MASK 0x00001000L 73 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_MASK 0x00002000L 74 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_COUNT_MASK 0x000F0000L 75 | //GENERIC_I2C_DATA 76 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_RW__SHIFT 0x0 77 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA__SHIFT 0x8 78 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX__SHIFT 0x10 79 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_WRITE__SHIFT 0x1f 80 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_RW_MASK 0x00000001L 81 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_MASK 0x0000FF00L 82 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_MASK 0x000F0000L 83 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_WRITE_MASK 0x80000000L 84 | //GENERIC_I2C_PIN_SELECTION 85 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SCL_PIN_SEL__SHIFT 0x0 86 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SDA_PIN_SEL__SHIFT 0x8 87 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SCL_PIN_SEL_MASK 0x0000007FL 88 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SDA_PIN_SEL_MASK 0x00007F00L 89 | 90 | static const struct i2c_registers i2c_registers = { 91 | I2C_GENERIC_REG_LIST() 92 | }; 93 | 94 | static const struct i2c_mask i2c_masks = { 95 | I2C_GENERIC_MASK_SH_LIST(_MASK) 96 | }; 97 | 98 | static const struct i2c_shift i2c_shifts = { 99 | I2C_GENERIC_MASK_SH_LIST(__SHIFT) 100 | }; 101 | 102 | const struct asic_context asic_context_navi = { 103 | .i2c_registers = &i2c_registers, 104 | .i2c_shifts = &i2c_shifts, 105 | .i2c_masks = &i2c_masks 106 | }; 107 | -------------------------------------------------------------------------------- /asic/asic-polaris.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | #include "asic-registers.h" 3 | 4 | #define mmGENERIC_I2C_CONTROL 0x16f4 5 | #define mmGENERIC_I2C_INTERRUPT_CONTROL 0x16f5 6 | #define mmGENERIC_I2C_STATUS 0x16f6 7 | #define mmGENERIC_I2C_SPEED 0x16f7 8 | #define mmGENERIC_I2C_SETUP 0x16f8 9 | #define mmGENERIC_I2C_TRANSACTION 0x16f9 10 | #define mmGENERIC_I2C_DATA 0x16fa 11 | #define mmGENERIC_I2C_PIN_SELECTION 0x16fb 12 | 13 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_GO_MASK 0x1 14 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_GO__SHIFT 0x0 15 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SOFT_RESET_MASK 0x2 16 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SOFT_RESET__SHIFT 0x1 17 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SEND_RESET_MASK 0x4 18 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SEND_RESET__SHIFT 0x2 19 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_ENABLE_MASK 0x8 20 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_ENABLE__SHIFT 0x3 21 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_DBG_REF_SEL_MASK 0x80000000 22 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_DBG_REF_SEL__SHIFT 0x1f 23 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_INT_MASK 0x1 24 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_INT__SHIFT 0x0 25 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_ACK_MASK 0x2 26 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_ACK__SHIFT 0x1 27 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_MASK_MASK 0x4 28 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_MASK__SHIFT 0x2 29 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_OCCURRED_MASK 0x100 30 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_OCCURRED__SHIFT 0x8 31 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_INT_MASK 0x200 32 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_INT__SHIFT 0x9 33 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_ACK_MASK 0x400 34 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_ACK__SHIFT 0xa 35 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_MASK_MASK 0x800 36 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_MASK__SHIFT 0xb 37 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_INT_TYPE_MASK 0x1000 38 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DDC_READ_REQUEST_INT_TYPE__SHIFT 0xc 39 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STATUS_MASK 0xf 40 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STATUS__SHIFT 0x0 41 | #define GENERIC_I2C_STATUS__GENERIC_I2C_DONE_MASK 0x10 42 | #define GENERIC_I2C_STATUS__GENERIC_I2C_DONE__SHIFT 0x4 43 | #define GENERIC_I2C_STATUS__GENERIC_I2C_ABORTED_MASK 0x20 44 | #define GENERIC_I2C_STATUS__GENERIC_I2C_ABORTED__SHIFT 0x5 45 | #define GENERIC_I2C_STATUS__GENERIC_I2C_TIMEOUT_MASK 0x40 46 | #define GENERIC_I2C_STATUS__GENERIC_I2C_TIMEOUT__SHIFT 0x6 47 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STOPPED_ON_NACK_MASK 0x200 48 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STOPPED_ON_NACK__SHIFT 0x9 49 | #define GENERIC_I2C_STATUS__GENERIC_I2C_NACK_MASK 0x400 50 | #define GENERIC_I2C_STATUS__GENERIC_I2C_NACK__SHIFT 0xa 51 | #define GENERIC_I2C_SPEED__GENERIC_I2C_THRESHOLD_MASK 0x3 52 | #define GENERIC_I2C_SPEED__GENERIC_I2C_THRESHOLD__SHIFT 0x0 53 | #define GENERIC_I2C_SPEED__GENERIC_I2C_DISABLE_FILTER_DURING_STALL_MASK 0x10 54 | #define GENERIC_I2C_SPEED__GENERIC_I2C_DISABLE_FILTER_DURING_STALL__SHIFT 0x4 55 | #define GENERIC_I2C_SPEED__GENERIC_I2C_START_STOP_TIMING_CNTL_MASK 0x300 56 | #define GENERIC_I2C_SPEED__GENERIC_I2C_START_STOP_TIMING_CNTL__SHIFT 0x8 57 | #define GENERIC_I2C_SPEED__GENERIC_I2C_PRESCALE_MASK 0xffff0000 58 | #define GENERIC_I2C_SPEED__GENERIC_I2C_PRESCALE__SHIFT 0x10 59 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_EN_MASK 0x1 60 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_EN__SHIFT 0x0 61 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_SEL_MASK 0x2 62 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_SEL__SHIFT 0x1 63 | #define GENERIC_I2C_SETUP__GENERIC_I2C_CLK_DRIVE_EN_MASK 0x80 64 | #define GENERIC_I2C_SETUP__GENERIC_I2C_CLK_DRIVE_EN__SHIFT 0x7 65 | #define GENERIC_I2C_SETUP__GENERIC_I2C_INTRA_BYTE_DELAY_MASK 0xff00 66 | #define GENERIC_I2C_SETUP__GENERIC_I2C_INTRA_BYTE_DELAY__SHIFT 0x8 67 | #define GENERIC_I2C_SETUP__GENERIC_I2C_TIME_LIMIT_MASK 0xff000000 68 | #define GENERIC_I2C_SETUP__GENERIC_I2C_TIME_LIMIT__SHIFT 0x18 69 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_RW_MASK 0x1 70 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_RW__SHIFT 0x0 71 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_ON_NACK_MASK 0x100 72 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_ON_NACK__SHIFT 0x8 73 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_ACK_ON_READ_MASK 0x200 74 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_ACK_ON_READ__SHIFT 0x9 75 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_START_MASK 0x1000 76 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_START__SHIFT 0xc 77 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_MASK 0x2000 78 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP__SHIFT 0xd 79 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_COUNT_MASK 0xf0000 80 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_COUNT__SHIFT 0x10 81 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_RW_MASK 0x1 82 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_RW__SHIFT 0x0 83 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_MASK 0xff00 84 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA__SHIFT 0x8 85 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_MASK 0xf0000 86 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX__SHIFT 0x10 87 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_WRITE_MASK 0x80000000 88 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_WRITE__SHIFT 0x1f 89 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SCL_PIN_SEL_MASK 0x7f 90 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SCL_PIN_SEL__SHIFT 0x0 91 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SDA_PIN_SEL_MASK 0x7f00 92 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SDA_PIN_SEL__SHIFT 0x8 93 | 94 | static const struct i2c_registers i2c_registers = { 95 | I2C_GENERIC_REG_LIST() 96 | }; 97 | 98 | static const struct i2c_mask i2c_masks = { 99 | I2C_GENERIC_MASK_SH_LIST(_MASK) 100 | }; 101 | 102 | static const struct i2c_shift i2c_shifts = { 103 | I2C_GENERIC_MASK_SH_LIST(__SHIFT) 104 | }; 105 | 106 | const struct asic_context asic_context_polaris = { 107 | .i2c_registers = &i2c_registers, 108 | .i2c_shifts = &i2c_shifts, 109 | .i2c_masks = &i2c_masks 110 | }; 111 | -------------------------------------------------------------------------------- /asic/asic-registers.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_AURA_GPU_REGISTERS_H 3 | #define _UAPI_AURA_GPU_REGISTERS_H 4 | 5 | #include 6 | 7 | #define SR(reg_name) .reg_name = mm ## reg_name 8 | 9 | #define I2C_GENERIC_REG_LIST()\ 10 | SR(GENERIC_I2C_CONTROL),\ 11 | SR(GENERIC_I2C_INTERRUPT_CONTROL),\ 12 | SR(GENERIC_I2C_STATUS),\ 13 | SR(GENERIC_I2C_SPEED),\ 14 | SR(GENERIC_I2C_SETUP),\ 15 | SR(GENERIC_I2C_TRANSACTION),\ 16 | SR(GENERIC_I2C_DATA),\ 17 | SR(GENERIC_I2C_PIN_SELECTION) 18 | 19 | #define I2C_SF(reg_name, field_name, post_fix)\ 20 | .field_name = reg_name ## __ ## field_name ## post_fix 21 | 22 | #define I2C_GENERIC_MASK_SH_LIST(mask_sh)\ 23 | I2C_SF(GENERIC_I2C_CONTROL, GENERIC_I2C_GO, mask_sh),\ 24 | I2C_SF(GENERIC_I2C_CONTROL, GENERIC_I2C_SOFT_RESET, mask_sh),\ 25 | I2C_SF(GENERIC_I2C_CONTROL, GENERIC_I2C_SEND_RESET, mask_sh),\ 26 | I2C_SF(GENERIC_I2C_CONTROL, GENERIC_I2C_ENABLE, mask_sh),\ 27 | I2C_SF(GENERIC_I2C_STATUS, GENERIC_I2C_STATUS, mask_sh),\ 28 | I2C_SF(GENERIC_I2C_STATUS, GENERIC_I2C_DONE, mask_sh),\ 29 | I2C_SF(GENERIC_I2C_STATUS, GENERIC_I2C_ABORTED, mask_sh),\ 30 | I2C_SF(GENERIC_I2C_STATUS, GENERIC_I2C_TIMEOUT, mask_sh),\ 31 | I2C_SF(GENERIC_I2C_STATUS, GENERIC_I2C_STOPPED_ON_NACK, mask_sh),\ 32 | I2C_SF(GENERIC_I2C_STATUS, GENERIC_I2C_NACK, mask_sh),\ 33 | I2C_SF(GENERIC_I2C_SPEED, GENERIC_I2C_THRESHOLD, mask_sh),\ 34 | I2C_SF(GENERIC_I2C_SPEED, GENERIC_I2C_DISABLE_FILTER_DURING_STALL, mask_sh),\ 35 | I2C_SF(GENERIC_I2C_SPEED, GENERIC_I2C_START_STOP_TIMING_CNTL, mask_sh),\ 36 | I2C_SF(GENERIC_I2C_SPEED, GENERIC_I2C_PRESCALE, mask_sh),\ 37 | I2C_SF(GENERIC_I2C_SETUP, GENERIC_I2C_DATA_DRIVE_EN, mask_sh),\ 38 | I2C_SF(GENERIC_I2C_SETUP, GENERIC_I2C_DATA_DRIVE_SEL, mask_sh),\ 39 | I2C_SF(GENERIC_I2C_SETUP, GENERIC_I2C_CLK_DRIVE_EN, mask_sh),\ 40 | I2C_SF(GENERIC_I2C_SETUP, GENERIC_I2C_INTRA_BYTE_DELAY, mask_sh),\ 41 | I2C_SF(GENERIC_I2C_SETUP, GENERIC_I2C_TIME_LIMIT, mask_sh),\ 42 | I2C_SF(GENERIC_I2C_TRANSACTION, GENERIC_I2C_RW, mask_sh),\ 43 | I2C_SF(GENERIC_I2C_TRANSACTION, GENERIC_I2C_STOP_ON_NACK, mask_sh),\ 44 | I2C_SF(GENERIC_I2C_TRANSACTION, GENERIC_I2C_ACK_ON_READ, mask_sh),\ 45 | I2C_SF(GENERIC_I2C_TRANSACTION, GENERIC_I2C_START, mask_sh),\ 46 | I2C_SF(GENERIC_I2C_TRANSACTION, GENERIC_I2C_STOP, mask_sh),\ 47 | I2C_SF(GENERIC_I2C_TRANSACTION, GENERIC_I2C_COUNT, mask_sh),\ 48 | I2C_SF(GENERIC_I2C_DATA, GENERIC_I2C_DATA_RW, mask_sh),\ 49 | I2C_SF(GENERIC_I2C_DATA, GENERIC_I2C_DATA, mask_sh),\ 50 | I2C_SF(GENERIC_I2C_DATA, GENERIC_I2C_INDEX, mask_sh),\ 51 | I2C_SF(GENERIC_I2C_DATA, GENERIC_I2C_INDEX_WRITE, mask_sh),\ 52 | I2C_SF(GENERIC_I2C_PIN_SELECTION, GENERIC_I2C_SDA_PIN_SEL, mask_sh),\ 53 | I2C_SF(GENERIC_I2C_PIN_SELECTION, GENERIC_I2C_SCL_PIN_SEL, mask_sh),\ 54 | I2C_SF(GENERIC_I2C_INTERRUPT_CONTROL, GENERIC_I2C_DONE_INT, mask_sh),\ 55 | I2C_SF(GENERIC_I2C_INTERRUPT_CONTROL, GENERIC_I2C_DONE_ACK, mask_sh),\ 56 | I2C_SF(GENERIC_I2C_INTERRUPT_CONTROL, GENERIC_I2C_DONE_MASK, mask_sh),\ 57 | 58 | struct i2c_registers { 59 | uint32_t GENERIC_I2C_SETUP; 60 | uint32_t GENERIC_I2C_SPEED; 61 | uint32_t GENERIC_I2C_STATUS; 62 | uint32_t GENERIC_I2C_CONTROL; 63 | uint32_t GENERIC_I2C_TRANSACTION; 64 | uint32_t GENERIC_I2C_DATA; 65 | uint32_t GENERIC_I2C_INTERRUPT_CONTROL; 66 | uint32_t GENERIC_I2C_PIN_SELECTION; 67 | }; 68 | 69 | struct i2c_mask { 70 | uint32_t GENERIC_I2C_GO; 71 | uint32_t GENERIC_I2C_SOFT_RESET; 72 | uint32_t GENERIC_I2C_SEND_RESET; 73 | uint32_t GENERIC_I2C_ENABLE; 74 | uint32_t GENERIC_I2C_DBG_REF_SEL; 75 | uint32_t GENERIC_I2C_STATUS; 76 | uint32_t GENERIC_I2C_DONE; 77 | uint32_t GENERIC_I2C_ABORTED; 78 | uint32_t GENERIC_I2C_TIMEOUT; 79 | uint32_t GENERIC_I2C_STOPPED_ON_NACK; 80 | uint32_t GENERIC_I2C_NACK; 81 | uint32_t GENERIC_I2C_THRESHOLD; 82 | uint32_t GENERIC_I2C_DISABLE_FILTER_DURING_STALL; 83 | uint32_t GENERIC_I2C_START_STOP_TIMING_CNTL; 84 | uint32_t GENERIC_I2C_PRESCALE; 85 | uint32_t GENERIC_I2C_DATA_DRIVE_EN; 86 | uint32_t GENERIC_I2C_DATA_DRIVE_SEL; 87 | uint32_t GENERIC_I2C_CLK_DRIVE_EN; 88 | uint32_t GENERIC_I2C_INTRA_BYTE_DELAY; 89 | uint32_t GENERIC_I2C_TIME_LIMIT; 90 | uint32_t GENERIC_I2C_RW; 91 | uint32_t GENERIC_I2C_STOP_ON_NACK; 92 | uint32_t GENERIC_I2C_ACK_ON_READ; 93 | uint32_t GENERIC_I2C_START; 94 | uint32_t GENERIC_I2C_STOP; 95 | uint32_t GENERIC_I2C_COUNT; 96 | uint32_t GENERIC_I2C_DATA_RW; 97 | uint32_t GENERIC_I2C_DATA; 98 | uint32_t GENERIC_I2C_INDEX; 99 | uint32_t GENERIC_I2C_INDEX_WRITE; 100 | uint32_t GENERIC_I2C_SCL_PIN_SEL; 101 | uint32_t GENERIC_I2C_SDA_PIN_SEL; 102 | uint32_t GENERIC_I2C_DONE_INT; 103 | uint32_t GENERIC_I2C_DONE_ACK; 104 | uint32_t GENERIC_I2C_DONE_MASK; 105 | }; 106 | 107 | struct i2c_shift { 108 | uint8_t GENERIC_I2C_GO; 109 | uint8_t GENERIC_I2C_SOFT_RESET; 110 | uint8_t GENERIC_I2C_SEND_RESET; 111 | uint8_t GENERIC_I2C_ENABLE; 112 | uint8_t GENERIC_I2C_DBG_REF_SEL; 113 | uint8_t GENERIC_I2C_STATUS; 114 | uint8_t GENERIC_I2C_DONE; 115 | uint8_t GENERIC_I2C_ABORTED; 116 | uint8_t GENERIC_I2C_TIMEOUT; 117 | uint8_t GENERIC_I2C_STOPPED_ON_NACK; 118 | uint8_t GENERIC_I2C_NACK; 119 | uint8_t GENERIC_I2C_THRESHOLD; 120 | uint8_t GENERIC_I2C_DISABLE_FILTER_DURING_STALL; 121 | uint8_t GENERIC_I2C_START_STOP_TIMING_CNTL; 122 | uint8_t GENERIC_I2C_PRESCALE; 123 | uint8_t GENERIC_I2C_DATA_DRIVE_EN; 124 | uint8_t GENERIC_I2C_DATA_DRIVE_SEL; 125 | uint8_t GENERIC_I2C_CLK_DRIVE_EN; 126 | uint8_t GENERIC_I2C_INTRA_BYTE_DELAY; 127 | uint8_t GENERIC_I2C_TIME_LIMIT; 128 | uint8_t GENERIC_I2C_RW; 129 | uint8_t GENERIC_I2C_STOP_ON_NACK; 130 | uint8_t GENERIC_I2C_ACK_ON_READ; 131 | uint8_t GENERIC_I2C_START; 132 | uint8_t GENERIC_I2C_STOP; 133 | uint8_t GENERIC_I2C_COUNT; 134 | uint8_t GENERIC_I2C_DATA_RW; 135 | uint8_t GENERIC_I2C_DATA; 136 | uint8_t GENERIC_I2C_INDEX; 137 | uint8_t GENERIC_I2C_INDEX_WRITE; 138 | uint8_t GENERIC_I2C_SCL_PIN_SEL; 139 | uint8_t GENERIC_I2C_SDA_PIN_SEL; 140 | uint8_t GENERIC_I2C_DONE_INT; 141 | uint8_t GENERIC_I2C_DONE_ACK; 142 | uint8_t GENERIC_I2C_DONE_MASK; 143 | }; 144 | 145 | struct asic_context { 146 | const struct i2c_registers *i2c_registers; 147 | const struct i2c_shift *i2c_shifts; 148 | const struct i2c_mask *i2c_masks; 149 | }; 150 | 151 | 152 | extern const struct asic_context asic_context_polaris; 153 | extern const struct asic_context asic_context_vega; 154 | extern const struct asic_context asic_context_navi; 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /asic/asic-types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_AURA_GPU_ASIC_TYPES_H 3 | #define _UAPI_AURA_GPU_ASIC_TYPES_H 4 | #include 5 | 6 | enum aura_asic_type { 7 | CHIP_NVIDIA = 0, 8 | CHIP_POLARIS10, // AMDGPU_FAMILY_VI DCE_VERSION_11_2 9 | CHIP_POLARIS11, // AMDGPU_FAMILY_VI DCE_VERSION_11_2 10 | CHIP_POLARIS12, // AMDGPU_FAMILY_VI DCE_VERSION_11_2 11 | CHIP_VEGAM, // AMDGPU_FAMILY_VI DCE_VERSION_11_2 12 | CHIP_VEGA10, // AMDGPU_FAMILY_AI DCE_VERSION_12_0 13 | CHIP_VEGA12, // AMDGPU_FAMILY_AI DCE_VERSION_12_0 14 | CHIP_VEGA20, // AMDGPU_FAMILY_AI DCE_VERSION_12_1 15 | CHIP_NAVI10, // AMDGPU_FAMILY_NV DCN_VERSION_2_0 16 | CHIP_LAST, 17 | }; 18 | 19 | static inline bool asic_is_valid(enum aura_asic_type asic) 20 | { 21 | return asic >= CHIP_NVIDIA && asic <= CHIP_LAST; 22 | } 23 | 24 | static inline bool asic_is_nvidia(enum aura_asic_type asic) 25 | { 26 | return asic_is_valid(asic) && asic == CHIP_NVIDIA; 27 | } 28 | 29 | static inline bool asic_is_amd(enum aura_asic_type asic) 30 | { 31 | return asic_is_valid(asic) && asic != CHIP_NVIDIA; 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /asic/asic-vega.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | #include "asic-registers.h" 3 | 4 | #define mmGENERIC_I2C_CONTROL 0x15a4 5 | #define mmGENERIC_I2C_INTERRUPT_CONTROL 0x15a5 6 | #define mmGENERIC_I2C_STATUS 0x15a6 7 | #define mmGENERIC_I2C_SPEED 0x15a7 8 | #define mmGENERIC_I2C_SETUP 0x15a8 9 | #define mmGENERIC_I2C_TRANSACTION 0x15a9 10 | #define mmGENERIC_I2C_DATA 0x15aa 11 | #define mmGENERIC_I2C_PIN_SELECTION 0x15ab 12 | 13 | //GENERIC_I2C_CONTROL 14 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_GO__SHIFT 0x0 15 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SOFT_RESET__SHIFT 0x1 16 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SEND_RESET__SHIFT 0x2 17 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_ENABLE__SHIFT 0x3 18 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_GO_MASK 0x00000001L 19 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SOFT_RESET_MASK 0x00000002L 20 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_SEND_RESET_MASK 0x00000004L 21 | #define GENERIC_I2C_CONTROL__GENERIC_I2C_ENABLE_MASK 0x00000008L 22 | //GENERIC_I2C_INTERRUPT_CONTROL 23 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_INT__SHIFT 0x0 24 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_ACK__SHIFT 0x1 25 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_MASK__SHIFT 0x2 26 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_INT_MASK 0x00000001L 27 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_ACK_MASK 0x00000002L 28 | #define GENERIC_I2C_INTERRUPT_CONTROL__GENERIC_I2C_DONE_MASK_MASK 0x00000004L 29 | //GENERIC_I2C_STATUS 30 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STATUS__SHIFT 0x0 31 | #define GENERIC_I2C_STATUS__GENERIC_I2C_DONE__SHIFT 0x4 32 | #define GENERIC_I2C_STATUS__GENERIC_I2C_ABORTED__SHIFT 0x5 33 | #define GENERIC_I2C_STATUS__GENERIC_I2C_TIMEOUT__SHIFT 0x6 34 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STOPPED_ON_NACK__SHIFT 0x9 35 | #define GENERIC_I2C_STATUS__GENERIC_I2C_NACK__SHIFT 0xa 36 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STATUS_MASK 0x0000000FL 37 | #define GENERIC_I2C_STATUS__GENERIC_I2C_DONE_MASK 0x00000010L 38 | #define GENERIC_I2C_STATUS__GENERIC_I2C_ABORTED_MASK 0x00000020L 39 | #define GENERIC_I2C_STATUS__GENERIC_I2C_TIMEOUT_MASK 0x00000040L 40 | #define GENERIC_I2C_STATUS__GENERIC_I2C_STOPPED_ON_NACK_MASK 0x00000200L 41 | #define GENERIC_I2C_STATUS__GENERIC_I2C_NACK_MASK 0x00000400L 42 | //GENERIC_I2C_SPEED 43 | #define GENERIC_I2C_SPEED__GENERIC_I2C_THRESHOLD__SHIFT 0x0 44 | #define GENERIC_I2C_SPEED__GENERIC_I2C_DISABLE_FILTER_DURING_STALL__SHIFT 0x4 45 | #define GENERIC_I2C_SPEED__GENERIC_I2C_START_STOP_TIMING_CNTL__SHIFT 0x8 46 | #define GENERIC_I2C_SPEED__GENERIC_I2C_PRESCALE__SHIFT 0x10 47 | #define GENERIC_I2C_SPEED__GENERIC_I2C_THRESHOLD_MASK 0x00000003L 48 | #define GENERIC_I2C_SPEED__GENERIC_I2C_DISABLE_FILTER_DURING_STALL_MASK 0x00000010L 49 | #define GENERIC_I2C_SPEED__GENERIC_I2C_START_STOP_TIMING_CNTL_MASK 0x00000300L 50 | #define GENERIC_I2C_SPEED__GENERIC_I2C_PRESCALE_MASK 0xFFFF0000L 51 | //GENERIC_I2C_SETUP 52 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_EN__SHIFT 0x0 53 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_SEL__SHIFT 0x1 54 | #define GENERIC_I2C_SETUP__GENERIC_I2C_CLK_DRIVE_EN__SHIFT 0x7 55 | #define GENERIC_I2C_SETUP__GENERIC_I2C_INTRA_BYTE_DELAY__SHIFT 0x8 56 | #define GENERIC_I2C_SETUP__GENERIC_I2C_TIME_LIMIT__SHIFT 0x18 57 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_EN_MASK 0x00000001L 58 | #define GENERIC_I2C_SETUP__GENERIC_I2C_DATA_DRIVE_SEL_MASK 0x00000002L 59 | #define GENERIC_I2C_SETUP__GENERIC_I2C_CLK_DRIVE_EN_MASK 0x00000080L 60 | #define GENERIC_I2C_SETUP__GENERIC_I2C_INTRA_BYTE_DELAY_MASK 0x0000FF00L 61 | #define GENERIC_I2C_SETUP__GENERIC_I2C_TIME_LIMIT_MASK 0xFF000000L 62 | //GENERIC_I2C_TRANSACTION 63 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_RW__SHIFT 0x0 64 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_ON_NACK__SHIFT 0x8 65 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_ACK_ON_READ__SHIFT 0x9 66 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_START__SHIFT 0xc 67 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP__SHIFT 0xd 68 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_COUNT__SHIFT 0x10 69 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_RW_MASK 0x00000001L 70 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_ON_NACK_MASK 0x00000100L 71 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_ACK_ON_READ_MASK 0x00000200L 72 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_START_MASK 0x00001000L 73 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_STOP_MASK 0x00002000L 74 | #define GENERIC_I2C_TRANSACTION__GENERIC_I2C_COUNT_MASK 0x000F0000L 75 | //GENERIC_I2C_DATA 76 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_RW__SHIFT 0x0 77 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA__SHIFT 0x8 78 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX__SHIFT 0x10 79 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_WRITE__SHIFT 0x1f 80 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_RW_MASK 0x00000001L 81 | #define GENERIC_I2C_DATA__GENERIC_I2C_DATA_MASK 0x0000FF00L 82 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_MASK 0x000F0000L 83 | #define GENERIC_I2C_DATA__GENERIC_I2C_INDEX_WRITE_MASK 0x80000000L 84 | //GENERIC_I2C_PIN_SELECTION 85 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SCL_PIN_SEL__SHIFT 0x0 86 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SDA_PIN_SEL__SHIFT 0x8 87 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SCL_PIN_SEL_MASK 0x0000007FL 88 | #define GENERIC_I2C_PIN_SELECTION__GENERIC_I2C_SDA_PIN_SEL_MASK 0x00007F00L 89 | 90 | static const struct i2c_registers i2c_registers = { 91 | I2C_GENERIC_REG_LIST() 92 | }; 93 | 94 | static const struct i2c_mask i2c_masks = { 95 | I2C_GENERIC_MASK_SH_LIST(_MASK) 96 | }; 97 | 98 | static const struct i2c_shift i2c_shifts = { 99 | I2C_GENERIC_MASK_SH_LIST(__SHIFT) 100 | }; 101 | 102 | const struct asic_context asic_context_vega = { 103 | .i2c_registers = &i2c_registers, 104 | .i2c_shifts = &i2c_shifts, 105 | .i2c_masks = &i2c_masks 106 | }; 107 | -------------------------------------------------------------------------------- /atom/atom-bits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Advanced Micro Devices, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | * OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * Author: Stanislaw Skowronek 23 | */ 24 | 25 | #ifndef ATOM_BITS_H 26 | #define ATOM_BITS_H 27 | 28 | static inline uint8_t get_u8(void const *bios, int ptr) 29 | { 30 | return ((unsigned char *)bios)[ptr]; 31 | } 32 | #define U8(ptr) get_u8(ctx->ctx->bios,(ptr)) 33 | #define CU8(ptr) get_u8(ctx->bios,(ptr)) 34 | static inline uint16_t get_u16(void const *bios, int ptr) 35 | { 36 | return get_u8(bios,ptr)|(((uint16_t)get_u8(bios,ptr+1))<<8); 37 | } 38 | #define U16(ptr) get_u16(ctx->ctx->bios,(ptr)) 39 | #define CU16(ptr) get_u16(ctx->bios,(ptr)) 40 | static inline uint32_t get_u32(void const *bios, int ptr) 41 | { 42 | return get_u16(bios,ptr)|(((uint32_t)get_u16(bios,ptr+2))<<16); 43 | } 44 | #define U32(ptr) get_u32(ctx->ctx->bios,(ptr)) 45 | #define CU32(ptr) get_u32(ctx->bios,(ptr)) 46 | #define CSTR(ptr) (((char *)(ctx->bios))+(ptr)) 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /atom/atom-names.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Advanced Micro Devices, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | * OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * Author: Stanislaw Skowronek 23 | */ 24 | 25 | #ifndef ATOM_NAMES_H 26 | #define ATOM_NAMES_H 27 | 28 | #include "atom.h" 29 | 30 | #ifdef ATOM_DEBUG 31 | 32 | #define ATOM_OP_NAMES_CNT 123 33 | static char *atom_op_names[ATOM_OP_NAMES_CNT]={ 34 | "RESERVED", "MOVE_REG", "MOVE_PS", "MOVE_WS", "MOVE_FB", "MOVE_PLL", 35 | "MOVE_MC", "AND_REG", "AND_PS", "AND_WS", "AND_FB", "AND_PLL", "AND_MC", 36 | "OR_REG", "OR_PS", "OR_WS", "OR_FB", "OR_PLL", "OR_MC", "SHIFT_LEFT_REG", 37 | "SHIFT_LEFT_PS", "SHIFT_LEFT_WS", "SHIFT_LEFT_FB", "SHIFT_LEFT_PLL", 38 | "SHIFT_LEFT_MC", "SHIFT_RIGHT_REG", "SHIFT_RIGHT_PS", "SHIFT_RIGHT_WS", 39 | "SHIFT_RIGHT_FB", "SHIFT_RIGHT_PLL", "SHIFT_RIGHT_MC", "MUL_REG", 40 | "MUL_PS", "MUL_WS", "MUL_FB", "MUL_PLL", "MUL_MC", "DIV_REG", "DIV_PS", 41 | "DIV_WS", "DIV_FB", "DIV_PLL", "DIV_MC", "ADD_REG", "ADD_PS", "ADD_WS", 42 | "ADD_FB", "ADD_PLL", "ADD_MC", "SUB_REG", "SUB_PS", "SUB_WS", "SUB_FB", 43 | "SUB_PLL", "SUB_MC", "SET_ATI_PORT", "SET_PCI_PORT", "SET_SYS_IO_PORT", 44 | "SET_REG_BLOCK", "SET_FB_BASE", "COMPARE_REG", "COMPARE_PS", 45 | "COMPARE_WS", "COMPARE_FB", "COMPARE_PLL", "COMPARE_MC", "SWITCH", 46 | "JUMP", "JUMP_EQUAL", "JUMP_BELOW", "JUMP_ABOVE", "JUMP_BELOW_OR_EQUAL", 47 | "JUMP_ABOVE_OR_EQUAL", "JUMP_NOT_EQUAL", "TEST_REG", "TEST_PS", "TEST_WS", 48 | "TEST_FB", "TEST_PLL", "TEST_MC", "DELAY_MILLISEC", "DELAY_MICROSEC", 49 | "CALL_TABLE", "REPEAT", "CLEAR_REG", "CLEAR_PS", "CLEAR_WS", "CLEAR_FB", 50 | "CLEAR_PLL", "CLEAR_MC", "NOP", "EOT", "MASK_REG", "MASK_PS", "MASK_WS", 51 | "MASK_FB", "MASK_PLL", "MASK_MC", "POST_CARD", "BEEP", "SAVE_REG", 52 | "RESTORE_REG", "SET_DATA_BLOCK", "XOR_REG", "XOR_PS", "XOR_WS", "XOR_FB", 53 | "XOR_PLL", "XOR_MC", "SHL_REG", "SHL_PS", "SHL_WS", "SHL_FB", "SHL_PLL", 54 | "SHL_MC", "SHR_REG", "SHR_PS", "SHR_WS", "SHR_FB", "SHR_PLL", "SHR_MC", 55 | "DEBUG", "CTB_DS", 56 | }; 57 | 58 | #define ATOM_TABLE_NAMES_CNT 74 59 | static char *atom_table_names[ATOM_TABLE_NAMES_CNT]={ 60 | "ASIC_Init", "GetDisplaySurfaceSize", "ASIC_RegistersInit", 61 | "VRAM_BlockVenderDetection", "SetClocksRatio", "MemoryControllerInit", 62 | "GPIO_PinInit", "MemoryParamAdjust", "DVOEncoderControl", 63 | "GPIOPinControl", "SetEngineClock", "SetMemoryClock", "SetPixelClock", 64 | "DynamicClockGating", "ResetMemoryDLL", "ResetMemoryDevice", 65 | "MemoryPLLInit", "EnableMemorySelfRefresh", "AdjustMemoryController", 66 | "EnableASIC_StaticPwrMgt", "ASIC_StaticPwrMgtStatusChange", 67 | "DAC_LoadDetection", "TMDS2EncoderControl", "LCD1OutputControl", 68 | "DAC1EncoderControl", "DAC2EncoderControl", "DVOOutputControl", 69 | "CV1OutputControl", "SetCRTC_DPM_State", "TVEncoderControl", 70 | "TMDS1EncoderControl", "LVDSEncoderControl", "TV1OutputControl", 71 | "EnableScaler", "BlankCRTC", "EnableCRTC", "GetPixelClock", 72 | "EnableVGA_Render", "EnableVGA_Access", "SetCRTC_Timing", 73 | "SetCRTC_OverScan", "SetCRTC_Replication", "SelectCRTC_Source", 74 | "EnableGraphSurfaces", "UpdateCRTC_DoubleBufferRegisters", 75 | "LUT_AutoFill", "EnableHW_IconCursor", "GetMemoryClock", 76 | "GetEngineClock", "SetCRTC_UsingDTDTiming", "TVBootUpStdPinDetection", 77 | "DFP2OutputControl", "VRAM_BlockDetectionByStrap", "MemoryCleanUp", 78 | "ReadEDIDFromHWAssistedI2C", "WriteOneByteToHWAssistedI2C", 79 | "ReadHWAssistedI2CStatus", "SpeedFanControl", "PowerConnectorDetection", 80 | "MC_Synchronization", "ComputeMemoryEnginePLL", "MemoryRefreshConversion", 81 | "VRAM_GetCurrentInfoBlock", "DynamicMemorySettings", "MemoryTraining", 82 | "EnableLVDS_SS", "DFP1OutputControl", "SetVoltage", "CRT1OutputControl", 83 | "CRT2OutputControl", "SetupHWAssistedI2CStatus", "ClockSource", 84 | "MemoryDeviceInit", "EnableYUV", 85 | }; 86 | 87 | #define ATOM_IO_NAMES_CNT 5 88 | static char *atom_io_names[ATOM_IO_NAMES_CNT]={ 89 | "MM", "PLL", "MC", "PCIE", "PCIE PORT", 90 | }; 91 | 92 | #else 93 | 94 | #define ATOM_OP_NAMES_CNT 0 95 | #define ATOM_TABLE_NAMES_CNT 0 96 | #define ATOM_IO_NAMES_CNT 0 97 | 98 | #endif 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /atom/atom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Advanced Micro Devices, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | * OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * Author: Stanislaw Skowronek 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define ATOM_DEBUG 1 32 | 33 | #include "atom.h" 34 | #include "atom-names.h" 35 | #include "atom-bits.h" 36 | 37 | #define ATOM_COND_ABOVE 0 38 | #define ATOM_COND_ABOVEOREQUAL 1 39 | #define ATOM_COND_ALWAYS 2 40 | #define ATOM_COND_BELOW 3 41 | #define ATOM_COND_BELOWOREQUAL 4 42 | #define ATOM_COND_EQUAL 5 43 | #define ATOM_COND_NOTEQUAL 6 44 | 45 | #define ATOM_PORT_ATI 0 46 | #define ATOM_PORT_PCI 1 47 | #define ATOM_PORT_SYSIO 2 48 | 49 | #define ATOM_UNIT_MICROSEC 0 50 | #define ATOM_UNIT_MILLISEC 1 51 | 52 | #define PLL_INDEX 2 53 | #define PLL_DATA 3 54 | 55 | typedef struct { 56 | struct atom_context *ctx; 57 | uint32_t *ps, *ws; 58 | int ps_shift; 59 | uint16_t start; 60 | unsigned last_jump; 61 | unsigned long last_jump_jiffies; 62 | bool abort; 63 | } atom_exec_context; 64 | 65 | int atom_debug = 0; 66 | static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params); 67 | int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params); 68 | 69 | static uint32_t atom_arg_mask[8] = { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, 0xFF000000 }; 70 | static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 }; 71 | static int atom_dst_to_src[8][4] = { 72 | /* translate destination alignment field to the source alignment encoding */ 73 | {0, 0, 0, 0}, 74 | {1, 2, 3, 0}, 75 | {1, 2, 3, 0}, 76 | {1, 2, 3, 0}, 77 | {4, 5, 6, 7}, 78 | {4, 5, 6, 7}, 79 | {4, 5, 6, 7}, 80 | {4, 5, 6, 7}, 81 | }; 82 | static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 }; 83 | static int debug_depth = 0; 84 | 85 | #ifdef ATOM_DEBUG 86 | static void debug_print_spaces(int n) 87 | { 88 | while (n--) 89 | printk(" "); 90 | } 91 | 92 | #define ADEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0) 93 | #define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0) 94 | #define _DEBUG(...) do { printk(KERN_DEBUG __VA_ARGS__); } while (0) 95 | #else 96 | #define ADEBUG(...) do { } while (0) 97 | #define SDEBUG(...) do { } while (0) 98 | #define _DEBUG(...) do { } while (0) 99 | #endif 100 | 101 | static uint32_t atom_iio_execute(struct atom_context *ctx, int base, uint32_t index, uint32_t data) 102 | { 103 | uint32_t temp = 0xCDCDCDCD; 104 | 105 | while (1) 106 | switch (CU8(base)) { 107 | case ATOM_IIO_NOP: 108 | base++; 109 | break; 110 | case ATOM_IIO_READ: 111 | temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1)); 112 | base += 3; 113 | break; 114 | case ATOM_IIO_WRITE: 115 | ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp); 116 | base += 3; 117 | break; 118 | case ATOM_IIO_CLEAR: 119 | temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 2)); 120 | base += 3; 121 | break; 122 | case ATOM_IIO_SET: 123 | temp |= (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 2); 124 | base += 3; 125 | break; 126 | case ATOM_IIO_MOVE_INDEX: 127 | temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 3)); 128 | temp |= ((index >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + 3); 129 | base += 4; 130 | break; 131 | case ATOM_IIO_MOVE_DATA: 132 | temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 3)); 133 | temp |= ((data >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + 3); 134 | base += 4; 135 | break; 136 | case ATOM_IIO_MOVE_ATTR: 137 | temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base + 3)); 138 | temp |= ((ctx-> io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + 3); 139 | base += 4; 140 | break; 141 | case ATOM_IIO_END: 142 | return temp; 143 | default: 144 | pr_info("Unknown IIO opcode\n"); 145 | return 0; 146 | } 147 | } 148 | 149 | static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr, uint32_t *saved, int print) 150 | { 151 | uint32_t idx, val = 0xCDCDCDCD, align, arg; 152 | struct atom_context *gctx = ctx->ctx; 153 | arg = attr & 7; 154 | align = (attr >> 3) & 7; 155 | switch (arg) { 156 | case ATOM_ARG_REG: 157 | idx = U16(*ptr); 158 | (*ptr) += 2; 159 | if (print) 160 | ADEBUG("REG[0x%04X]", idx); 161 | idx += gctx->reg_block; 162 | switch (gctx->io_mode) { 163 | case ATOM_IO_MM: 164 | val = gctx->card->reg_read(gctx->card, idx); 165 | break; 166 | case ATOM_IO_PCI: 167 | pr_info("PCI registers are not implemented\n"); 168 | return 0; 169 | case ATOM_IO_SYSIO: 170 | pr_info("SYSIO registers are not implemented\n"); 171 | return 0; 172 | default: 173 | if (!(gctx->io_mode & 0x80)) { 174 | pr_info("Bad IO mode\n"); 175 | return 0; 176 | } 177 | if (!gctx->iio[gctx->io_mode & 0x7F]) { 178 | pr_info("Undefined indirect IO read method %d\n", 179 | gctx->io_mode & 0x7F); 180 | return 0; 181 | } 182 | val = 183 | atom_iio_execute(gctx, 184 | gctx->iio[gctx->io_mode & 0x7F], 185 | idx, 0); 186 | } 187 | break; 188 | case ATOM_ARG_PS: 189 | idx = U8(*ptr); 190 | (*ptr)++; 191 | /* get_unaligned_le32 avoids unaligned accesses from atombios 192 | * tables, noticed on a DEC Alpha. */ 193 | val = get_unaligned_le32((u32 *)&ctx->ps[idx]); 194 | if (print) 195 | ADEBUG("PS[0x%02X,0x%04X]", idx, val); 196 | break; 197 | case ATOM_ARG_WS: 198 | idx = U8(*ptr); 199 | (*ptr)++; 200 | if (print) 201 | ADEBUG("WS[0x%02X]", idx); 202 | switch (idx) { 203 | case ATOM_WS_QUOTIENT: 204 | val = gctx->divmul[0]; 205 | break; 206 | case ATOM_WS_REMAINDER: 207 | val = gctx->divmul[1]; 208 | break; 209 | case ATOM_WS_DATAPTR: 210 | val = gctx->data_block; 211 | break; 212 | case ATOM_WS_SHIFT: 213 | val = gctx->shift; 214 | break; 215 | case ATOM_WS_OR_MASK: 216 | val = 1 << gctx->shift; 217 | break; 218 | case ATOM_WS_AND_MASK: 219 | val = ~(1 << gctx->shift); 220 | break; 221 | case ATOM_WS_FB_WINDOW: 222 | val = gctx->fb_base; 223 | break; 224 | case ATOM_WS_ATTRIBUTES: 225 | val = gctx->io_attr; 226 | break; 227 | case ATOM_WS_REGPTR: 228 | val = gctx->reg_block; 229 | break; 230 | default: 231 | val = ctx->ws[idx]; 232 | } 233 | break; 234 | case ATOM_ARG_ID: 235 | idx = U16(*ptr); 236 | (*ptr) += 2; 237 | if (print) { 238 | if (gctx->data_block) 239 | ADEBUG("ID[0x%04X+%04X]", idx, gctx->data_block); 240 | else 241 | ADEBUG("ID[0x%04X]", idx); 242 | } 243 | val = U32(idx + gctx->data_block); 244 | break; 245 | case ATOM_ARG_FB: 246 | idx = U8(*ptr); 247 | (*ptr)++; 248 | if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) { 249 | ADEBUG("ATOM: fb read beyond scratch region: %d vs. %d\n", 250 | gctx->fb_base + (idx * 4), gctx->scratch_size_bytes); 251 | val = 0; 252 | } else 253 | val = gctx->scratch[(gctx->fb_base / 4) + idx]; 254 | if (print) 255 | ADEBUG("FB[0x%02X]", idx); 256 | break; 257 | case ATOM_ARG_IMM: 258 | switch (align) { 259 | case ATOM_SRC_DWORD: 260 | val = U32(*ptr); 261 | (*ptr) += 4; 262 | if (print) 263 | ADEBUG("IMM 0x%08X\n", val); 264 | return val; 265 | case ATOM_SRC_WORD0: 266 | case ATOM_SRC_WORD8: 267 | case ATOM_SRC_WORD16: 268 | val = U16(*ptr); 269 | (*ptr) += 2; 270 | if (print) 271 | ADEBUG("IMM 0x%04X\n", val); 272 | return val; 273 | case ATOM_SRC_BYTE0: 274 | case ATOM_SRC_BYTE8: 275 | case ATOM_SRC_BYTE16: 276 | case ATOM_SRC_BYTE24: 277 | val = U8(*ptr); 278 | (*ptr)++; 279 | if (print) 280 | ADEBUG("IMM 0x%02X\n", val); 281 | return val; 282 | } 283 | return 0; 284 | case ATOM_ARG_PLL: 285 | idx = U8(*ptr); 286 | (*ptr)++; 287 | if (print) 288 | ADEBUG("PLL[0x%02X]", idx); 289 | val = gctx->card->pll_read(gctx->card, idx); 290 | break; 291 | case ATOM_ARG_MC: 292 | idx = U8(*ptr); 293 | (*ptr)++; 294 | if (print) 295 | ADEBUG("MC[0x%02X]", idx); 296 | val = gctx->card->mc_read(gctx->card, idx); 297 | break; 298 | } 299 | if (saved) 300 | *saved = val; 301 | val &= atom_arg_mask[align]; 302 | val >>= atom_arg_shift[align]; 303 | if (print) 304 | switch (align) { 305 | case ATOM_SRC_DWORD: 306 | ADEBUG(".[31:0] -> 0x%08X\n", val); 307 | break; 308 | case ATOM_SRC_WORD0: 309 | ADEBUG(".[15:0] -> 0x%04X\n", val); 310 | break; 311 | case ATOM_SRC_WORD8: 312 | ADEBUG(".[23:8] -> 0x%04X\n", val); 313 | break; 314 | case ATOM_SRC_WORD16: 315 | ADEBUG(".[31:16] -> 0x%04X\n", val); 316 | break; 317 | case ATOM_SRC_BYTE0: 318 | ADEBUG(".[7:0] -> 0x%02X\n", val); 319 | break; 320 | case ATOM_SRC_BYTE8: 321 | ADEBUG(".[15:8] -> 0x%02X\n", val); 322 | break; 323 | case ATOM_SRC_BYTE16: 324 | ADEBUG(".[23:16] -> 0x%02X\n", val); 325 | break; 326 | case ATOM_SRC_BYTE24: 327 | ADEBUG(".[31:24] -> 0x%02X\n", val); 328 | break; 329 | } 330 | return val; 331 | } 332 | 333 | static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr) 334 | { 335 | uint32_t align = (attr >> 3) & 7, arg = attr & 7; 336 | switch (arg) { 337 | case ATOM_ARG_REG: 338 | case ATOM_ARG_ID: 339 | (*ptr) += 2; 340 | break; 341 | case ATOM_ARG_PLL: 342 | case ATOM_ARG_MC: 343 | case ATOM_ARG_PS: 344 | case ATOM_ARG_WS: 345 | case ATOM_ARG_FB: 346 | (*ptr)++; 347 | break; 348 | case ATOM_ARG_IMM: 349 | switch (align) { 350 | case ATOM_SRC_DWORD: 351 | (*ptr) += 4; 352 | return; 353 | case ATOM_SRC_WORD0: 354 | case ATOM_SRC_WORD8: 355 | case ATOM_SRC_WORD16: 356 | (*ptr) += 2; 357 | return; 358 | case ATOM_SRC_BYTE0: 359 | case ATOM_SRC_BYTE8: 360 | case ATOM_SRC_BYTE16: 361 | case ATOM_SRC_BYTE24: 362 | (*ptr)++; 363 | return; 364 | } 365 | return; 366 | } 367 | } 368 | 369 | static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr) 370 | { 371 | return atom_get_src_int(ctx, attr, ptr, NULL, 1); 372 | } 373 | 374 | static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr) 375 | { 376 | uint32_t val = 0xCDCDCDCD; 377 | 378 | switch (align) { 379 | case ATOM_SRC_DWORD: 380 | val = U32(*ptr); 381 | (*ptr) += 4; 382 | break; 383 | case ATOM_SRC_WORD0: 384 | case ATOM_SRC_WORD8: 385 | case ATOM_SRC_WORD16: 386 | val = U16(*ptr); 387 | (*ptr) += 2; 388 | break; 389 | case ATOM_SRC_BYTE0: 390 | case ATOM_SRC_BYTE8: 391 | case ATOM_SRC_BYTE16: 392 | case ATOM_SRC_BYTE24: 393 | val = U8(*ptr); 394 | (*ptr)++; 395 | break; 396 | } 397 | return val; 398 | } 399 | 400 | static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t *saved, int print) 401 | { 402 | return atom_get_src_int(ctx, arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3] << 3, ptr, saved, print); 403 | } 404 | 405 | static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr) 406 | { 407 | atom_skip_src_int(ctx, arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3] << 3, ptr); 408 | } 409 | 410 | static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t val, uint32_t saved) 411 | { 412 | uint32_t align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val = val, idx; 413 | struct atom_context *gctx = ctx->ctx; 414 | old_val &= atom_arg_mask[align] >> atom_arg_shift[align]; 415 | val <<= atom_arg_shift[align]; 416 | val &= atom_arg_mask[align]; 417 | saved &= ~atom_arg_mask[align]; 418 | val |= saved; 419 | switch (arg) { 420 | case ATOM_ARG_REG: 421 | idx = U16(*ptr); 422 | (*ptr) += 2; 423 | ADEBUG("REG[0x%04X]", idx); 424 | idx += gctx->reg_block; 425 | switch (gctx->io_mode) { 426 | case ATOM_IO_MM: 427 | if (idx == 0) 428 | gctx->card->reg_write(gctx->card, idx, val << 2); 429 | else 430 | gctx->card->reg_write(gctx->card, idx, val); 431 | break; 432 | case ATOM_IO_PCI: 433 | pr_info("PCI registers are not implemented\n"); 434 | return; 435 | case ATOM_IO_SYSIO: 436 | pr_info("SYSIO registers are not implemented\n"); 437 | return; 438 | default: 439 | if (!(gctx->io_mode & 0x80)) { 440 | pr_info("Bad IO mode\n"); 441 | return; 442 | } 443 | if (!gctx->iio[gctx->io_mode & 0xFF]) { 444 | pr_info("Undefined indirect IO write method %d\n", 445 | gctx->io_mode & 0x7F); 446 | return; 447 | } 448 | atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF], 449 | idx, val); 450 | } 451 | break; 452 | case ATOM_ARG_PS: 453 | idx = U8(*ptr); 454 | (*ptr)++; 455 | ADEBUG("PS[0x%02X]", idx); 456 | ctx->ps[idx] = cpu_to_le32(val); 457 | break; 458 | case ATOM_ARG_WS: 459 | idx = U8(*ptr); 460 | (*ptr)++; 461 | ADEBUG("WS[0x%02X]", idx); 462 | switch (idx) { 463 | case ATOM_WS_QUOTIENT: 464 | gctx->divmul[0] = val; 465 | break; 466 | case ATOM_WS_REMAINDER: 467 | gctx->divmul[1] = val; 468 | break; 469 | case ATOM_WS_DATAPTR: 470 | gctx->data_block = val; 471 | break; 472 | case ATOM_WS_SHIFT: 473 | gctx->shift = val; 474 | break; 475 | case ATOM_WS_OR_MASK: 476 | case ATOM_WS_AND_MASK: 477 | break; 478 | case ATOM_WS_FB_WINDOW: 479 | gctx->fb_base = val; 480 | break; 481 | case ATOM_WS_ATTRIBUTES: 482 | gctx->io_attr = val; 483 | break; 484 | case ATOM_WS_REGPTR: 485 | gctx->reg_block = val; 486 | break; 487 | default: 488 | ctx->ws[idx] = val; 489 | } 490 | break; 491 | case ATOM_ARG_FB: 492 | idx = U8(*ptr); 493 | (*ptr)++; 494 | if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) { 495 | ADEBUG("ATOM: fb write beyond scratch region: %d vs. %d\n", gctx->fb_base + (idx * 4), gctx->scratch_size_bytes); 496 | } else { 497 | _DEBUG("ATOM: scratch write 0x%x to index %d", val, (gctx->fb_base / 4) + idx); 498 | gctx->scratch[(gctx->fb_base / 4) + idx] = val; 499 | } 500 | ADEBUG("FB[0x%02X]", idx); 501 | break; 502 | case ATOM_ARG_PLL: 503 | idx = U8(*ptr); 504 | (*ptr)++; 505 | ADEBUG("PLL[0x%02X]", idx); 506 | gctx->card->pll_write(gctx->card, idx, val); 507 | break; 508 | case ATOM_ARG_MC: 509 | idx = U8(*ptr); 510 | (*ptr)++; 511 | ADEBUG("MC[0x%02X]", idx); 512 | gctx->card->mc_write(gctx->card, idx, val); 513 | return; 514 | } 515 | switch (align) { 516 | case ATOM_SRC_DWORD: 517 | ADEBUG(".[31:0] <- 0x%08X\n", old_val); 518 | break; 519 | case ATOM_SRC_WORD0: 520 | ADEBUG(".[15:0] <- 0x%04X\n", old_val); 521 | break; 522 | case ATOM_SRC_WORD8: 523 | ADEBUG(".[23:8] <- 0x%04X\n", old_val); 524 | break; 525 | case ATOM_SRC_WORD16: 526 | ADEBUG(".[31:16] <- 0x%04X\n", old_val); 527 | break; 528 | case ATOM_SRC_BYTE0: 529 | ADEBUG(".[7:0] <- 0x%02X\n", old_val); 530 | break; 531 | case ATOM_SRC_BYTE8: 532 | ADEBUG(".[15:8] <- 0x%02X\n", old_val); 533 | break; 534 | case ATOM_SRC_BYTE16: 535 | ADEBUG(".[23:16] <- 0x%02X\n", old_val); 536 | break; 537 | case ATOM_SRC_BYTE24: 538 | ADEBUG(".[31:24] <- 0x%02X\n", old_val); 539 | break; 540 | } 541 | } 542 | 543 | static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg) 544 | { 545 | uint8_t attr = U8((*ptr)++); 546 | uint32_t dst, src, saved; 547 | int dptr = *ptr; 548 | SDEBUG(" dst: "); 549 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 550 | SDEBUG(" src: "); 551 | src = atom_get_src(ctx, attr, ptr); 552 | dst += src; 553 | SDEBUG(" dst: "); 554 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 555 | } 556 | 557 | static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg) 558 | { 559 | uint8_t attr = U8((*ptr)++); 560 | uint32_t dst, src, saved; 561 | int dptr = *ptr; 562 | SDEBUG(" dst: "); 563 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 564 | SDEBUG(" src: "); 565 | src = atom_get_src(ctx, attr, ptr); 566 | dst &= src; 567 | SDEBUG(" dst: "); 568 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 569 | } 570 | 571 | static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg) 572 | { 573 | printk("ATOM BIOS beeped!\n"); 574 | } 575 | 576 | static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) 577 | { 578 | int idx = U8((*ptr)++); 579 | int r = 0; 580 | 581 | if (idx < ATOM_TABLE_NAMES_CNT) 582 | SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); 583 | else 584 | SDEBUG(" table: %d\n", idx); 585 | if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) 586 | r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); 587 | if (r) { 588 | ctx->abort = true; 589 | } 590 | } 591 | 592 | static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) 593 | { 594 | uint8_t attr = U8((*ptr)++); 595 | uint32_t saved; 596 | int dptr = *ptr; 597 | attr &= 0x38; 598 | attr |= atom_def_dst[attr >> 3] << 6; 599 | atom_get_dst(ctx, arg, attr, ptr, &saved, 0); 600 | SDEBUG(" dst: "); 601 | atom_put_dst(ctx, arg, attr, &dptr, 0, saved); 602 | } 603 | 604 | static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg) 605 | { 606 | uint8_t attr = U8((*ptr)++); 607 | uint32_t dst, src; 608 | SDEBUG(" src1: "); 609 | dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 610 | SDEBUG(" src2: "); 611 | src = atom_get_src(ctx, attr, ptr); 612 | ctx->ctx->cs_equal = (dst == src); 613 | ctx->ctx->cs_above = (dst > src); 614 | SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE", ctx->ctx->cs_above ? "GT" : "LE"); 615 | } 616 | 617 | static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) 618 | { 619 | unsigned count = U8((*ptr)++); 620 | SDEBUG(" count: %d\n", count); 621 | if (arg == ATOM_UNIT_MICROSEC) 622 | udelay(count); 623 | // else if (!drm_can_sleep()) 624 | // mdelay(count); 625 | else 626 | msleep(count); 627 | } 628 | 629 | static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg) 630 | { 631 | uint8_t attr = U8((*ptr)++); 632 | uint32_t dst, src; 633 | SDEBUG(" src1: "); 634 | dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 635 | SDEBUG(" src2: "); 636 | src = atom_get_src(ctx, attr, ptr); 637 | if (src != 0) { 638 | ctx->ctx->divmul[0] = dst / src; 639 | ctx->ctx->divmul[1] = dst % src; 640 | } else { 641 | ctx->ctx->divmul[0] = 0; 642 | ctx->ctx->divmul[1] = 0; 643 | } 644 | } 645 | 646 | static void atom_op_div32(atom_exec_context *ctx, int *ptr, int arg) 647 | { 648 | uint64_t val64; 649 | uint8_t attr = U8((*ptr)++); 650 | uint32_t dst, src; 651 | SDEBUG(" src1: "); 652 | dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 653 | SDEBUG(" src2: "); 654 | src = atom_get_src(ctx, attr, ptr); 655 | if (src != 0) { 656 | val64 = dst; 657 | val64 |= ((uint64_t)ctx->ctx->divmul[1]) << 32; 658 | do_div(val64, src); 659 | ctx->ctx->divmul[0] = lower_32_bits(val64); 660 | ctx->ctx->divmul[1] = upper_32_bits(val64); 661 | } else { 662 | ctx->ctx->divmul[0] = 0; 663 | ctx->ctx->divmul[1] = 0; 664 | } 665 | } 666 | 667 | static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg) 668 | { 669 | /* functionally, a nop */ 670 | } 671 | 672 | static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) 673 | { 674 | int execute = 0, target = U16(*ptr); 675 | unsigned long cjiffies; 676 | 677 | (*ptr) += 2; 678 | switch (arg) { 679 | case ATOM_COND_ABOVE: 680 | execute = ctx->ctx->cs_above; 681 | break; 682 | case ATOM_COND_ABOVEOREQUAL: 683 | execute = ctx->ctx->cs_above || ctx->ctx->cs_equal; 684 | break; 685 | case ATOM_COND_ALWAYS: 686 | execute = 1; 687 | break; 688 | case ATOM_COND_BELOW: 689 | execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal); 690 | break; 691 | case ATOM_COND_BELOWOREQUAL: 692 | execute = !ctx->ctx->cs_above; 693 | break; 694 | case ATOM_COND_EQUAL: 695 | execute = ctx->ctx->cs_equal; 696 | break; 697 | case ATOM_COND_NOTEQUAL: 698 | execute = !ctx->ctx->cs_equal; 699 | break; 700 | } 701 | if (arg != ATOM_COND_ALWAYS) 702 | SDEBUG(" taken: %s\n", execute ? "yes" : "no"); 703 | SDEBUG(" target: 0x%04X\n", target); 704 | if (execute) { 705 | if (ctx->last_jump == (ctx->start + target)) { 706 | cjiffies = jiffies; 707 | if (time_after(cjiffies, ctx->last_jump_jiffies)) { 708 | cjiffies -= ctx->last_jump_jiffies; 709 | if ((jiffies_to_msecs(cjiffies) > 5000)) { 710 | ADEBUG("atombios stuck in loop for more than 5secs aborting\n"); 711 | ctx->abort = true; 712 | } 713 | } else { 714 | /* jiffies wrap around we will just wait a little longer */ 715 | ctx->last_jump_jiffies = jiffies; 716 | } 717 | } else { 718 | ctx->last_jump = ctx->start + target; 719 | ctx->last_jump_jiffies = jiffies; 720 | } 721 | *ptr = ctx->start + target; 722 | } 723 | } 724 | 725 | static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) 726 | { 727 | uint8_t attr = U8((*ptr)++); 728 | uint32_t dst, mask, src, saved; 729 | int dptr = *ptr; 730 | SDEBUG(" dst: "); 731 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 732 | mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr); 733 | SDEBUG(" mask: 0x%08x", mask); 734 | SDEBUG(" src: "); 735 | src = atom_get_src(ctx, attr, ptr); 736 | dst &= mask; 737 | dst |= src; 738 | SDEBUG(" dst: "); 739 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 740 | } 741 | 742 | static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg) 743 | { 744 | uint8_t attr = U8((*ptr)++); 745 | uint32_t src, saved; 746 | int dptr = *ptr; 747 | if (((attr >> 3) & 7) != ATOM_SRC_DWORD) 748 | atom_get_dst(ctx, arg, attr, ptr, &saved, 0); 749 | else { 750 | atom_skip_dst(ctx, arg, attr, ptr); 751 | saved = 0xCDCDCDCD; 752 | } 753 | SDEBUG(" src: "); 754 | src = atom_get_src(ctx, attr, ptr); 755 | SDEBUG(" dst: "); 756 | atom_put_dst(ctx, arg, attr, &dptr, src, saved); 757 | } 758 | 759 | static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg) 760 | { 761 | uint8_t attr = U8((*ptr)++); 762 | uint32_t dst, src; 763 | SDEBUG(" src1: "); 764 | dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 765 | SDEBUG(" src2: "); 766 | src = atom_get_src(ctx, attr, ptr); 767 | ctx->ctx->divmul[0] = dst * src; 768 | } 769 | 770 | static void atom_op_mul32(atom_exec_context *ctx, int *ptr, int arg) 771 | { 772 | uint64_t val64; 773 | uint8_t attr = U8((*ptr)++); 774 | uint32_t dst, src; 775 | SDEBUG(" src1: "); 776 | dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 777 | SDEBUG(" src2: "); 778 | src = atom_get_src(ctx, attr, ptr); 779 | val64 = (uint64_t)dst * (uint64_t)src; 780 | ctx->ctx->divmul[0] = lower_32_bits(val64); 781 | ctx->ctx->divmul[1] = upper_32_bits(val64); 782 | } 783 | 784 | static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg) 785 | { 786 | /* nothing */ 787 | } 788 | 789 | static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg) 790 | { 791 | uint8_t attr = U8((*ptr)++); 792 | uint32_t dst, src, saved; 793 | int dptr = *ptr; 794 | SDEBUG(" dst: "); 795 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 796 | SDEBUG(" src: "); 797 | src = atom_get_src(ctx, attr, ptr); 798 | dst |= src; 799 | SDEBUG(" dst: "); 800 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 801 | } 802 | 803 | static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg) 804 | { 805 | uint8_t val = U8((*ptr)++); 806 | SDEBUG("POST card output: 0x%02X\n", val); 807 | } 808 | 809 | static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg) 810 | { 811 | pr_info("unimplemented!\n"); 812 | } 813 | 814 | static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg) 815 | { 816 | pr_info("unimplemented!\n"); 817 | } 818 | 819 | static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg) 820 | { 821 | pr_info("unimplemented!\n"); 822 | } 823 | 824 | static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg) 825 | { 826 | int idx = U8(*ptr); 827 | (*ptr)++; 828 | SDEBUG(" block: %d\n", idx); 829 | if (!idx) 830 | ctx->ctx->data_block = 0; 831 | else if (idx == 255) 832 | ctx->ctx->data_block = ctx->start; 833 | else 834 | ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx); 835 | SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block); 836 | } 837 | 838 | static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg) 839 | { 840 | uint8_t attr = U8((*ptr)++); 841 | SDEBUG(" fb_base: "); 842 | ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr); 843 | } 844 | 845 | static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg) 846 | { 847 | int port; 848 | switch (arg) { 849 | case ATOM_PORT_ATI: 850 | port = U16(*ptr); 851 | if (port < ATOM_IO_NAMES_CNT) 852 | SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]); 853 | else 854 | SDEBUG(" port: %d\n", port); 855 | if (!port) 856 | ctx->ctx->io_mode = ATOM_IO_MM; 857 | else 858 | ctx->ctx->io_mode = ATOM_IO_IIO | port; 859 | (*ptr) += 2; 860 | break; 861 | case ATOM_PORT_PCI: 862 | ctx->ctx->io_mode = ATOM_IO_PCI; 863 | (*ptr)++; 864 | break; 865 | case ATOM_PORT_SYSIO: 866 | ctx->ctx->io_mode = ATOM_IO_SYSIO; 867 | (*ptr)++; 868 | break; 869 | } 870 | } 871 | 872 | static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) 873 | { 874 | ctx->ctx->reg_block = U16(*ptr); 875 | (*ptr) += 2; 876 | SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); 877 | } 878 | 879 | static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg) 880 | { 881 | uint8_t attr = U8((*ptr)++), shift; 882 | uint32_t saved, dst; 883 | int dptr = *ptr; 884 | attr &= 0x38; 885 | attr |= atom_def_dst[attr >> 3] << 6; 886 | SDEBUG(" dst: "); 887 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 888 | shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); 889 | SDEBUG(" shift: %d\n", shift); 890 | dst <<= shift; 891 | SDEBUG(" dst: "); 892 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 893 | } 894 | 895 | static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg) 896 | { 897 | uint8_t attr = U8((*ptr)++), shift; 898 | uint32_t saved, dst; 899 | int dptr = *ptr; 900 | attr &= 0x38; 901 | attr |= atom_def_dst[attr >> 3] << 6; 902 | SDEBUG(" dst: "); 903 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 904 | shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); 905 | SDEBUG(" shift: %d\n", shift); 906 | dst >>= shift; 907 | SDEBUG(" dst: "); 908 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 909 | } 910 | 911 | static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) 912 | { 913 | uint8_t attr = U8((*ptr)++), shift; 914 | uint32_t saved, dst; 915 | int dptr = *ptr; 916 | uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; 917 | SDEBUG(" dst: "); 918 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 919 | /* op needs to full dst value */ 920 | dst = saved; 921 | shift = atom_get_src(ctx, attr, ptr); 922 | SDEBUG(" shift: %d\n", shift); 923 | dst <<= shift; 924 | dst &= atom_arg_mask[dst_align]; 925 | dst >>= atom_arg_shift[dst_align]; 926 | SDEBUG(" dst: "); 927 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 928 | } 929 | 930 | static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) 931 | { 932 | uint8_t attr = U8((*ptr)++), shift; 933 | uint32_t saved, dst; 934 | int dptr = *ptr; 935 | uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3]; 936 | SDEBUG(" dst: "); 937 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 938 | /* op needs to full dst value */ 939 | dst = saved; 940 | shift = atom_get_src(ctx, attr, ptr); 941 | SDEBUG(" shift: %d\n", shift); 942 | dst >>= shift; 943 | dst &= atom_arg_mask[dst_align]; 944 | dst >>= atom_arg_shift[dst_align]; 945 | SDEBUG(" dst: "); 946 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 947 | } 948 | 949 | static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg) 950 | { 951 | uint8_t attr = U8((*ptr)++); 952 | uint32_t dst, src, saved; 953 | int dptr = *ptr; 954 | SDEBUG(" dst: "); 955 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 956 | SDEBUG(" src: "); 957 | src = atom_get_src(ctx, attr, ptr); 958 | dst -= src; 959 | SDEBUG(" dst: "); 960 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 961 | } 962 | 963 | static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg) 964 | { 965 | uint8_t attr = U8((*ptr)++); 966 | uint32_t src, val, target; 967 | SDEBUG(" switch: "); 968 | src = atom_get_src(ctx, attr, ptr); 969 | while (U16(*ptr) != ATOM_CASE_END) 970 | if (U8(*ptr) == ATOM_CASE_MAGIC) { 971 | (*ptr)++; 972 | SDEBUG(" case: "); 973 | val = 974 | atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM, 975 | ptr); 976 | target = U16(*ptr); 977 | if (val == src) { 978 | SDEBUG(" target: %04X\n", target); 979 | *ptr = ctx->start + target; 980 | return; 981 | } 982 | (*ptr) += 2; 983 | } else { 984 | pr_info("Bad case\n"); 985 | return; 986 | } 987 | (*ptr) += 2; 988 | } 989 | 990 | static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg) 991 | { 992 | uint8_t attr = U8((*ptr)++); 993 | uint32_t dst, src; 994 | SDEBUG(" src1: "); 995 | dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); 996 | SDEBUG(" src2: "); 997 | src = atom_get_src(ctx, attr, ptr); 998 | ctx->ctx->cs_equal = ((dst & src) == 0); 999 | SDEBUG(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE"); 1000 | } 1001 | 1002 | static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg) 1003 | { 1004 | uint8_t attr = U8((*ptr)++); 1005 | uint32_t dst, src, saved; 1006 | int dptr = *ptr; 1007 | SDEBUG(" dst: "); 1008 | dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); 1009 | SDEBUG(" src: "); 1010 | src = atom_get_src(ctx, attr, ptr); 1011 | dst ^= src; 1012 | SDEBUG(" dst: "); 1013 | atom_put_dst(ctx, arg, attr, &dptr, dst, saved); 1014 | } 1015 | 1016 | static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg) 1017 | { 1018 | uint8_t val = U8((*ptr)++); 1019 | SDEBUG("DEBUG output: 0x%02X\n", val); 1020 | } 1021 | 1022 | static void atom_op_processds(atom_exec_context *ctx, int *ptr, int arg) 1023 | { 1024 | uint16_t val = U16(*ptr); 1025 | (*ptr) += val + 2; 1026 | SDEBUG("PROCESSDS output: 0x%02X\n", val); 1027 | } 1028 | 1029 | static struct { 1030 | void (*func) (atom_exec_context *, int *, int); 1031 | int arg; 1032 | } opcode_table[ATOM_OP_CNT] = { 1033 | { 1034 | NULL, 0}, { 1035 | atom_op_move, ATOM_ARG_REG}, { 1036 | atom_op_move, ATOM_ARG_PS}, { 1037 | atom_op_move, ATOM_ARG_WS}, { 1038 | atom_op_move, ATOM_ARG_FB}, { 1039 | atom_op_move, ATOM_ARG_PLL}, { 1040 | atom_op_move, ATOM_ARG_MC}, { 1041 | atom_op_and, ATOM_ARG_REG}, { 1042 | atom_op_and, ATOM_ARG_PS}, { 1043 | atom_op_and, ATOM_ARG_WS}, { 1044 | atom_op_and, ATOM_ARG_FB}, { 1045 | atom_op_and, ATOM_ARG_PLL}, { 1046 | atom_op_and, ATOM_ARG_MC}, { 1047 | atom_op_or, ATOM_ARG_REG}, { 1048 | atom_op_or, ATOM_ARG_PS}, { 1049 | atom_op_or, ATOM_ARG_WS}, { 1050 | atom_op_or, ATOM_ARG_FB}, { 1051 | atom_op_or, ATOM_ARG_PLL}, { 1052 | atom_op_or, ATOM_ARG_MC}, { 1053 | atom_op_shift_left, ATOM_ARG_REG}, { 1054 | atom_op_shift_left, ATOM_ARG_PS}, { 1055 | atom_op_shift_left, ATOM_ARG_WS}, { 1056 | atom_op_shift_left, ATOM_ARG_FB}, { 1057 | atom_op_shift_left, ATOM_ARG_PLL}, { 1058 | atom_op_shift_left, ATOM_ARG_MC}, { 1059 | atom_op_shift_right, ATOM_ARG_REG}, { 1060 | atom_op_shift_right, ATOM_ARG_PS}, { 1061 | atom_op_shift_right, ATOM_ARG_WS}, { 1062 | atom_op_shift_right, ATOM_ARG_FB}, { 1063 | atom_op_shift_right, ATOM_ARG_PLL}, { 1064 | atom_op_shift_right, ATOM_ARG_MC}, { 1065 | atom_op_mul, ATOM_ARG_REG}, { 1066 | atom_op_mul, ATOM_ARG_PS}, { 1067 | atom_op_mul, ATOM_ARG_WS}, { 1068 | atom_op_mul, ATOM_ARG_FB}, { 1069 | atom_op_mul, ATOM_ARG_PLL}, { 1070 | atom_op_mul, ATOM_ARG_MC}, { 1071 | atom_op_div, ATOM_ARG_REG}, { 1072 | atom_op_div, ATOM_ARG_PS}, { 1073 | atom_op_div, ATOM_ARG_WS}, { 1074 | atom_op_div, ATOM_ARG_FB}, { 1075 | atom_op_div, ATOM_ARG_PLL}, { 1076 | atom_op_div, ATOM_ARG_MC}, { 1077 | atom_op_add, ATOM_ARG_REG}, { 1078 | atom_op_add, ATOM_ARG_PS}, { 1079 | atom_op_add, ATOM_ARG_WS}, { 1080 | atom_op_add, ATOM_ARG_FB}, { 1081 | atom_op_add, ATOM_ARG_PLL}, { 1082 | atom_op_add, ATOM_ARG_MC}, { 1083 | atom_op_sub, ATOM_ARG_REG}, { 1084 | atom_op_sub, ATOM_ARG_PS}, { 1085 | atom_op_sub, ATOM_ARG_WS}, { 1086 | atom_op_sub, ATOM_ARG_FB}, { 1087 | atom_op_sub, ATOM_ARG_PLL}, { 1088 | atom_op_sub, ATOM_ARG_MC}, { 1089 | atom_op_setport, ATOM_PORT_ATI}, { 1090 | atom_op_setport, ATOM_PORT_PCI}, { 1091 | atom_op_setport, ATOM_PORT_SYSIO}, { 1092 | atom_op_setregblock, 0}, { 1093 | atom_op_setfbbase, 0}, { 1094 | atom_op_compare, ATOM_ARG_REG}, { 1095 | atom_op_compare, ATOM_ARG_PS}, { 1096 | atom_op_compare, ATOM_ARG_WS}, { 1097 | atom_op_compare, ATOM_ARG_FB}, { 1098 | atom_op_compare, ATOM_ARG_PLL}, { 1099 | atom_op_compare, ATOM_ARG_MC}, { 1100 | atom_op_switch, 0}, { 1101 | atom_op_jump, ATOM_COND_ALWAYS}, { 1102 | atom_op_jump, ATOM_COND_EQUAL}, { 1103 | atom_op_jump, ATOM_COND_BELOW}, { 1104 | atom_op_jump, ATOM_COND_ABOVE}, { 1105 | atom_op_jump, ATOM_COND_BELOWOREQUAL}, { 1106 | atom_op_jump, ATOM_COND_ABOVEOREQUAL}, { 1107 | atom_op_jump, ATOM_COND_NOTEQUAL}, { 1108 | atom_op_test, ATOM_ARG_REG}, { 1109 | atom_op_test, ATOM_ARG_PS}, { 1110 | atom_op_test, ATOM_ARG_WS}, { 1111 | atom_op_test, ATOM_ARG_FB}, { 1112 | atom_op_test, ATOM_ARG_PLL}, { 1113 | atom_op_test, ATOM_ARG_MC}, { 1114 | atom_op_delay, ATOM_UNIT_MILLISEC}, { 1115 | atom_op_delay, ATOM_UNIT_MICROSEC}, { 1116 | atom_op_calltable, 0}, { 1117 | atom_op_repeat, 0}, { 1118 | atom_op_clear, ATOM_ARG_REG}, { 1119 | atom_op_clear, ATOM_ARG_PS}, { 1120 | atom_op_clear, ATOM_ARG_WS}, { 1121 | atom_op_clear, ATOM_ARG_FB}, { 1122 | atom_op_clear, ATOM_ARG_PLL}, { 1123 | atom_op_clear, ATOM_ARG_MC}, { 1124 | atom_op_nop, 0}, { 1125 | atom_op_eot, 0}, { 1126 | atom_op_mask, ATOM_ARG_REG}, { 1127 | atom_op_mask, ATOM_ARG_PS}, { 1128 | atom_op_mask, ATOM_ARG_WS}, { 1129 | atom_op_mask, ATOM_ARG_FB}, { 1130 | atom_op_mask, ATOM_ARG_PLL}, { 1131 | atom_op_mask, ATOM_ARG_MC}, { 1132 | atom_op_postcard, 0}, { 1133 | atom_op_beep, 0}, { 1134 | atom_op_savereg, 0}, { 1135 | atom_op_restorereg, 0}, { 1136 | atom_op_setdatablock, 0}, { 1137 | atom_op_xor, ATOM_ARG_REG}, { 1138 | atom_op_xor, ATOM_ARG_PS}, { 1139 | atom_op_xor, ATOM_ARG_WS}, { 1140 | atom_op_xor, ATOM_ARG_FB}, { 1141 | atom_op_xor, ATOM_ARG_PLL}, { 1142 | atom_op_xor, ATOM_ARG_MC}, { 1143 | atom_op_shl, ATOM_ARG_REG}, { 1144 | atom_op_shl, ATOM_ARG_PS}, { 1145 | atom_op_shl, ATOM_ARG_WS}, { 1146 | atom_op_shl, ATOM_ARG_FB}, { 1147 | atom_op_shl, ATOM_ARG_PLL}, { 1148 | atom_op_shl, ATOM_ARG_MC}, { 1149 | atom_op_shr, ATOM_ARG_REG}, { 1150 | atom_op_shr, ATOM_ARG_PS}, { 1151 | atom_op_shr, ATOM_ARG_WS}, { 1152 | atom_op_shr, ATOM_ARG_FB}, { 1153 | atom_op_shr, ATOM_ARG_PLL}, { 1154 | atom_op_shr, ATOM_ARG_MC}, { 1155 | atom_op_debug, 0}, { 1156 | atom_op_processds, 0}, { 1157 | atom_op_mul32, ATOM_ARG_PS}, { 1158 | atom_op_mul32, ATOM_ARG_WS}, { 1159 | atom_op_div32, ATOM_ARG_PS}, { 1160 | atom_op_div32, ATOM_ARG_WS}, 1161 | }; 1162 | 1163 | static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params) 1164 | { 1165 | int base = CU16(ctx->cmd_table + 4 + 2 * index); 1166 | int len, ws, ps, ptr; 1167 | unsigned char op; 1168 | atom_exec_context ectx; 1169 | int ret = 0; 1170 | 1171 | if (!base) 1172 | return -EINVAL; 1173 | 1174 | len = CU16(base + ATOM_CT_SIZE_PTR); 1175 | ws = CU8(base + ATOM_CT_WS_PTR); 1176 | ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK; 1177 | ptr = base + ATOM_CT_CODE_PTR; 1178 | 1179 | SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); 1180 | 1181 | ectx.ctx = ctx; 1182 | ectx.ps_shift = ps / 4; 1183 | ectx.start = base; 1184 | ectx.ps = params; 1185 | ectx.abort = false; 1186 | ectx.last_jump = 0; 1187 | if (ws) 1188 | ectx.ws = kcalloc(4, ws, GFP_KERNEL); 1189 | else 1190 | ectx.ws = NULL; 1191 | 1192 | debug_depth++; 1193 | while (1) { 1194 | op = CU8(ptr++); 1195 | if (op < ATOM_OP_NAMES_CNT) 1196 | SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1); 1197 | else 1198 | SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1); 1199 | if (ectx.abort) { 1200 | ADEBUG("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n", 1201 | base, len, ws, ps, ptr - 1); 1202 | ret = -EINVAL; 1203 | goto free; 1204 | } 1205 | 1206 | if (op < ATOM_OP_CNT && op > 0) 1207 | opcode_table[op].func(&ectx, &ptr, opcode_table[op].arg); 1208 | else 1209 | break; 1210 | 1211 | if (op == ATOM_OP_EOT) 1212 | break; 1213 | } 1214 | debug_depth--; 1215 | SDEBUG("<<\n"); 1216 | 1217 | free: 1218 | if (ws) 1219 | kfree(ectx.ws); 1220 | return ret; 1221 | } 1222 | 1223 | int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) 1224 | { 1225 | int r; 1226 | 1227 | mutex_lock(&ctx->mutex); 1228 | /* reset data block */ 1229 | ctx->data_block = 0; 1230 | /* reset reg block */ 1231 | ctx->reg_block = 0; 1232 | /* reset fb window */ 1233 | ctx->fb_base = 0; 1234 | /* reset io mode */ 1235 | ctx->io_mode = ATOM_IO_MM; 1236 | /* reset divmul */ 1237 | ctx->divmul[0] = 0; 1238 | ctx->divmul[1] = 0; 1239 | r = atom_execute_table_locked(ctx, index, params); 1240 | mutex_unlock(&ctx->mutex); 1241 | return r; 1242 | } 1243 | 1244 | static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; 1245 | 1246 | static void atom_index_iio(struct atom_context *ctx, int base) 1247 | { 1248 | ctx->iio = kzalloc(2 * 256, GFP_KERNEL); 1249 | if (!ctx->iio) 1250 | return; 1251 | while (CU8(base) == ATOM_IIO_START) { 1252 | ctx->iio[CU8(base + 1)] = base + 2; 1253 | base += 2; 1254 | while (CU8(base) != ATOM_IIO_END) 1255 | base += atom_iio_len[CU8(base)]; 1256 | base += 3; 1257 | } 1258 | } 1259 | 1260 | struct atom_context *atom_parse(struct card_info *card, void const *bios) 1261 | { 1262 | int base; 1263 | struct atom_context *ctx = kzalloc(sizeof(struct atom_context), GFP_KERNEL); 1264 | char *str; 1265 | u16 idx; 1266 | 1267 | if (!ctx) 1268 | return NULL; 1269 | 1270 | ctx->card = card; 1271 | ctx->bios = bios; 1272 | 1273 | ADEBUG("ATOM: Parsing BIOS"); 1274 | 1275 | if (CU16(0) != ATOM_BIOS_MAGIC) { 1276 | pr_info("Invalid BIOS magic\n"); 1277 | kfree(ctx); 1278 | return NULL; 1279 | } 1280 | if (strncmp (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC, strlen(ATOM_ATI_MAGIC))) { 1281 | pr_info("Invalid ATI magic\n"); 1282 | kfree(ctx); 1283 | return NULL; 1284 | } 1285 | 1286 | base = CU16(ATOM_ROM_TABLE_PTR); 1287 | if (strncmp (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC, strlen(ATOM_ROM_MAGIC))) { 1288 | pr_info("Invalid ATOM magic\n"); 1289 | kfree(ctx); 1290 | return NULL; 1291 | } 1292 | 1293 | ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR); 1294 | ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR); 1295 | atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4); 1296 | if (!ctx->iio) { 1297 | atom_destroy(ctx); 1298 | return NULL; 1299 | } 1300 | 1301 | idx = CU16(ATOM_ROM_PART_NUMBER_PTR); 1302 | if (idx == 0) 1303 | idx = 0x80; 1304 | 1305 | str = CSTR(idx); 1306 | if (*str != '\0') { 1307 | pr_info("ATOM BIOS: %s\n", str); 1308 | strlcpy(ctx->vbios_version, str, sizeof(ctx->vbios_version)); 1309 | } 1310 | 1311 | return ctx; 1312 | } 1313 | 1314 | int atom_asic_init(struct atom_context *ctx) 1315 | { 1316 | int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR); 1317 | uint32_t ps[16]; 1318 | int ret; 1319 | 1320 | memset(ps, 0, 64); 1321 | 1322 | ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR)); 1323 | ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR)); 1324 | if (!ps[0] || !ps[1]) 1325 | return 1; 1326 | 1327 | if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) 1328 | return 1; 1329 | ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps); 1330 | if (ret) 1331 | return ret; 1332 | 1333 | memset(ps, 0, 64); 1334 | 1335 | return ret; 1336 | } 1337 | 1338 | void atom_destroy(struct atom_context *ctx) 1339 | { 1340 | kfree(ctx->iio); 1341 | kfree(ctx); 1342 | } 1343 | 1344 | bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t * size, uint8_t * frev, uint8_t * crev, uint16_t * data_start) 1345 | { 1346 | int offset = index * 2 + 4; 1347 | int idx = CU16(ctx->data_table + offset); 1348 | u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4); 1349 | 1350 | if (!mdt[index]) 1351 | return false; 1352 | 1353 | if (size) 1354 | *size = CU16(idx); 1355 | if (frev) 1356 | *frev = CU8(idx + 2); 1357 | if (crev) 1358 | *crev = CU8(idx + 3); 1359 | *data_start = idx; 1360 | return true; 1361 | } 1362 | 1363 | bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev, uint8_t * crev) 1364 | { 1365 | int offset = index * 2 + 4; 1366 | int idx = CU16(ctx->cmd_table + offset); 1367 | u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4); 1368 | 1369 | if (!mct[index]) 1370 | return false; 1371 | 1372 | if (frev) 1373 | *frev = CU8(idx + 2); 1374 | if (crev) 1375 | *crev = CU8(idx + 3); 1376 | return true; 1377 | } 1378 | -------------------------------------------------------------------------------- /atom/atom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Advanced Micro Devices, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 | * OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * Author: Stanislaw Skowronek 23 | */ 24 | 25 | #ifndef ATOM_H 26 | #define ATOM_H 27 | 28 | #include 29 | #include 30 | #include "types.h" 31 | #include "atom-bits.h" 32 | 33 | #define ATOM_BIOS_MAGIC 0xAA55 34 | #define ATOM_ATI_MAGIC_PTR 0x30 35 | #define ATOM_ATI_MAGIC " 761295520" 36 | #define ATOM_ROM_TABLE_PTR 0x48 37 | #define ATOM_ROM_PART_NUMBER_PTR 0x6E 38 | 39 | #define ATOM_ROM_MAGIC "ATOM" 40 | #define ATOM_ROM_MAGIC_PTR 4 41 | 42 | #define ATOM_ROM_HEADER_PTR 0x48 43 | #define ATOM_IMAGE_SIZE_PTR 2 44 | #define ATOM_IMAGE_SIZE_UNIT 512 45 | 46 | #define ATOM_ROM_MSG_PTR 0x10 47 | #define ATOM_ROM_CMD_PTR 0x1E 48 | #define ATOM_ROM_DATA_PTR 0x20 49 | 50 | #define ATOM_CMD_INIT 0 51 | #define ATOM_CMD_SETSCLK 0x0A 52 | #define ATOM_CMD_SETMCLK 0x0B 53 | #define ATOM_CMD_SETPCLK 0x0C 54 | #define ATOM_CMD_SPDFANCNTL 0x39 55 | 56 | #define ATOM_DATA_FWI_PTR 0xC 57 | #define ATOM_DATA_IIO_PTR 0x32 58 | 59 | #define ATOM_FWI_DEFSCLK_PTR 8 60 | #define ATOM_FWI_DEFMCLK_PTR 0xC 61 | #define ATOM_FWI_MAXSCLK_PTR 0x24 62 | #define ATOM_FWI_MAXMCLK_PTR 0x28 63 | 64 | #define ATOM_CT_SIZE_PTR 0 65 | #define ATOM_CT_WS_PTR 4 66 | #define ATOM_CT_PS_PTR 5 67 | #define ATOM_CT_PS_MASK 0x7F 68 | #define ATOM_CT_CODE_PTR 6 69 | 70 | #define ATOM_OP_CNT 127 71 | #define ATOM_OP_EOT 91 72 | 73 | #define ATOM_CASE_MAGIC 0x63 74 | #define ATOM_CASE_END 0x5A5A 75 | 76 | #define ATOM_ARG_REG 0 77 | #define ATOM_ARG_PS 1 78 | #define ATOM_ARG_WS 2 79 | #define ATOM_ARG_FB 3 80 | #define ATOM_ARG_ID 4 81 | #define ATOM_ARG_IMM 5 82 | #define ATOM_ARG_PLL 6 83 | #define ATOM_ARG_MC 7 84 | 85 | #define ATOM_SRC_DWORD 0 86 | #define ATOM_SRC_WORD0 1 87 | #define ATOM_SRC_WORD8 2 88 | #define ATOM_SRC_WORD16 3 89 | #define ATOM_SRC_BYTE0 4 90 | #define ATOM_SRC_BYTE8 5 91 | #define ATOM_SRC_BYTE16 6 92 | #define ATOM_SRC_BYTE24 7 93 | 94 | #define ATOM_WS_QUOTIENT 0x40 95 | #define ATOM_WS_REMAINDER 0x41 96 | #define ATOM_WS_DATAPTR 0x42 97 | #define ATOM_WS_SHIFT 0x43 98 | #define ATOM_WS_OR_MASK 0x44 99 | #define ATOM_WS_AND_MASK 0x45 100 | #define ATOM_WS_FB_WINDOW 0x46 101 | #define ATOM_WS_ATTRIBUTES 0x47 102 | #define ATOM_WS_REGPTR 0x48 103 | 104 | #define ATOM_IIO_NOP 0 105 | #define ATOM_IIO_START 1 106 | #define ATOM_IIO_READ 2 107 | #define ATOM_IIO_WRITE 3 108 | #define ATOM_IIO_CLEAR 4 109 | #define ATOM_IIO_SET 5 110 | #define ATOM_IIO_MOVE_INDEX 6 111 | #define ATOM_IIO_MOVE_ATTR 7 112 | #define ATOM_IIO_MOVE_DATA 8 113 | #define ATOM_IIO_END 9 114 | 115 | #define ATOM_IO_MM 0 116 | #define ATOM_IO_PCI 1 117 | #define ATOM_IO_SYSIO 2 118 | #define ATOM_IO_IIO 0x80 119 | 120 | struct card_info { 121 | void (* reg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ 122 | uint32_t (* reg_read)(struct card_info *, uint32_t); /* filled by driver */ 123 | void (* ioreg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ 124 | uint32_t (* ioreg_read)(struct card_info *, uint32_t); /* filled by driver */ 125 | void (* mc_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ 126 | uint32_t (* mc_read)(struct card_info *, uint32_t); /* filled by driver */ 127 | void (* pll_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ 128 | uint32_t (* pll_read)(struct card_info *, uint32_t); /* filled by driver */ 129 | }; 130 | 131 | struct atom_context { 132 | struct card_info *card; 133 | struct mutex mutex; 134 | void const *bios; 135 | uint32_t cmd_table, data_table; 136 | uint16_t *iio; 137 | 138 | uint16_t data_block; 139 | uint32_t fb_base; 140 | uint32_t divmul[2]; 141 | uint16_t io_attr; 142 | uint16_t reg_block; 143 | uint8_t shift; 144 | int cs_equal, cs_above; 145 | int io_mode; 146 | uint32_t *scratch; 147 | int scratch_size_bytes; 148 | char vbios_version[20]; 149 | 150 | // uint32_t firmware_start_offset; 151 | // uint32_t firmware_size; 152 | // uint32_t scratch_reg_offset; 153 | }; 154 | 155 | extern int atom_debug; 156 | 157 | struct atom_context *atom_parse(struct card_info *, void const *); 158 | int atom_execute_table(struct atom_context *, int, uint32_t *); 159 | int atom_asic_init(struct atom_context *); 160 | void atom_destroy(struct atom_context *); 161 | bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start); 162 | bool atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev); 163 | // #include "atom-types.h" 164 | // #include "atombios.h" 165 | // #include "ObjectID.h" 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /atom/parser.c: -------------------------------------------------------------------------------- 1 | #include "atom.h" 2 | #include "atombios.h" 3 | 4 | #define GET_IMAGE(type, offset) ((type*)bios_get_image(bp->bios, offset, sizeof(type))) 5 | #define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table) 6 | 7 | 8 | uint8_t *bios_get_image(struct atom_bios *bios, uint32_t offset, uint32_t size) 9 | { 10 | if (offset + size < bios->size) 11 | return bios->data + offset; 12 | else 13 | return NULL; 14 | } 15 | 16 | struct atom_data_revision { 17 | uint32_t major; 18 | uint32_t minor; 19 | }; 20 | 21 | struct object_info_table { 22 | struct atom_data_revision revision; 23 | union { 24 | ATOM_OBJECT_HEADER *v1_1; 25 | ATOM_OBJECT_HEADER_V3 *v1_3; 26 | }; 27 | }; 28 | 29 | struct bios_parser { 30 | bool valid; 31 | // struct dc_bios base; 32 | 33 | struct atom_bios *bios; 34 | 35 | struct object_info_table object_info_tbl; 36 | uint32_t object_info_tbl_offset; 37 | ATOM_MASTER_DATA_TABLE *master_data_tbl; 38 | 39 | // const struct bios_parser_helper *bios_helper; 40 | 41 | // const struct command_table_helper *cmd_helper; 42 | // struct cmd_tbl cmd_tbl; 43 | 44 | // bool remap_device_tags; 45 | }; 46 | 47 | static void get_atom_data_table_revision(ATOM_COMMON_TABLE_HEADER *atom_data_tbl, struct atom_data_revision *tbl_revision) 48 | { 49 | if (!tbl_revision) 50 | return; 51 | 52 | /* initialize the revision to 0 which is invalid revision */ 53 | tbl_revision->major = 0; 54 | tbl_revision->minor = 0; 55 | 56 | if (!atom_data_tbl) 57 | return; 58 | 59 | tbl_revision->major = (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl); 60 | tbl_revision->minor = (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl); 61 | } 62 | 63 | bool bios_parser_init(struct bios_parser *bp, struct atom_bios *bios) 64 | { 65 | uint16_t *rom_header_offset = NULL; 66 | ATOM_ROM_HEADER *rom_header = NULL; 67 | ATOM_OBJECT_HEADER *object_info_tbl; 68 | struct atom_data_revision tbl_rev = {0}; 69 | 70 | bp->bios = bios; 71 | 72 | // if (!init) 73 | // return false; 74 | 75 | // if (!init->bios) 76 | // return false; 77 | 78 | // bp->base.funcs = &vbios_funcs; 79 | // bp->base.bios = init->bios; 80 | // bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT; 81 | // 82 | // bp->base.ctx = init->ctx; 83 | // bp->base.bios_local_image = NULL; 84 | 85 | rom_header_offset = GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER); 86 | if (!rom_header_offset) 87 | return false; 88 | 89 | rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset); 90 | if (!rom_header) 91 | return false; 92 | 93 | get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev); 94 | if (tbl_rev.major >= 2 && tbl_rev.minor >= 2) 95 | return false; 96 | 97 | bp->master_data_tbl = GET_IMAGE(ATOM_MASTER_DATA_TABLE, rom_header->usMasterDataTableOffset); 98 | if (!bp->master_data_tbl) 99 | return false; 100 | 101 | bp->object_info_tbl_offset = DATA_TABLES(Object_Header); 102 | if (!bp->object_info_tbl_offset) 103 | return false; 104 | 105 | object_info_tbl = GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset); 106 | if (!object_info_tbl) 107 | return false; 108 | 109 | get_atom_data_table_revision(&object_info_tbl->sHeader, &bp->object_info_tbl.revision); 110 | if (bp->object_info_tbl.revision.major == 1 && bp->object_info_tbl.revision.minor >= 3) { 111 | ATOM_OBJECT_HEADER_V3 *tbl_v3; 112 | 113 | tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3, bp->object_info_tbl_offset); 114 | if (!tbl_v3) 115 | return false; 116 | 117 | bp->object_info_tbl.v1_3 = tbl_v3; 118 | } else if (bp->object_info_tbl.revision.major == 1 119 | && bp->object_info_tbl.revision.minor >= 1) 120 | bp->object_info_tbl.v1_1 = object_info_tbl; 121 | else { 122 | return false; 123 | } 124 | 125 | // dal_bios_parser_init_cmd_tbl(bp); 126 | // dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version); 127 | 128 | // bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base); 129 | 130 | return true; 131 | } 132 | 133 | static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset) 134 | { 135 | ATOM_OBJECT_TABLE *table; 136 | 137 | uint32_t object_table_offset = bp->object_info_tbl_offset + offset; 138 | 139 | table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset); 140 | 141 | if (!table) 142 | return 0; 143 | else 144 | return table->ucNumberOfObjects; 145 | } 146 | 147 | uint8_t bios_parser_get_connectors_number(struct bios_parser *bp) 148 | { 149 | // struct bios_parser *bp = BP_FROM_DCB(dcb); 150 | 151 | return get_number_of_objects(bp, le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset)); 152 | } 153 | -------------------------------------------------------------------------------- /atom/types.h: -------------------------------------------------------------------------------- 1 | #ifndef _UAPI_AURA_ATOM_TYPES_H 2 | #define _UAPI_AURA_ATOM_TYPES_H 3 | 4 | #include 5 | 6 | // #define AMD_VBIOS_SIGNATURE " 761295520" 7 | // #define AMD_VBIOS_SIGNATURE_OFFSET 0x30 8 | // #define AMD_VBIOS_SIGNATURE_SIZE sizeof(AMD_VBIOS_SIGNATURE) 9 | // #define AMD_VBIOS_SIGNATURE_END (AMD_VBIOS_SIGNATURE_OFFSET + AMD_VBIOS_SIGNATURE_SIZE) 10 | // #define AMD_IS_VALID_VBIOS(p) ((p)[0] == 0x55 && (p)[1] == 0xAA) 11 | // #define AMD_VBIOS_LENGTH(p) ((p)[2] << 9) 12 | // 13 | // #define ATOM_ROM_PART_NUMBER_PTR 0x6E 14 | // #define ATOM_ROM_TABLE_PTR 0x48 15 | // #define ATOM_ROM_MSG_PTR 0x10 16 | // #define ATOM_ROM_CMD_PTR 0x1E 17 | // #define ATOM_ROM_DATA_PTR 0x20 18 | 19 | // #define ATOM_DEVICE_RESERVEDC_INDEX 0x0000000C 20 | // #define ATOM_DEVICE_RESERVEDD_INDEX 0x0000000D 21 | // #define ATOM_DEVICE_RESERVEDE_INDEX 0x0000000E 22 | #define ATOM_DEVICE_RESERVEDF_INDEX 0x0000000F 23 | // #define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_DFP3_INDEX+1) 24 | // #define ATOM_MAX_SUPPORTED_DEVICE_INFO_2 ATOM_MAX_SUPPORTED_DEVICE_INFO 25 | // #define ATOM_MAX_SUPPORTED_DEVICE_INFO_3 (ATOM_DEVICE_DFP5_INDEX + 1 ) 26 | 27 | #define ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION 0x2 28 | #define ATOM_MAX_SUPPORTED_DEVICE (ATOM_DEVICE_RESERVEDF_INDEX+1) 29 | 30 | #define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L 31 | #define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30 32 | // #define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 33 | // #define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0 34 | #define ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION 0x2 35 | 36 | #define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO 1 37 | 38 | #define MasterDataTableIndexOf(FieldName) (((char*)(&((ATOM_MASTER_LIST_OF_DATA_TABLES*)0)->FieldName)-(char*)0)/sizeof(uint16_t)) 39 | #define MasterCommandTableIndexOf(FieldName) (((char*)(&((ATOM_MASTER_LIST_OF_COMMAND_TABLES*)0)->FieldName)-(char*)0)/sizeof(uint16_t)) 40 | #define MasterTableIndexOf(master_table, table_name) (offsetof(master_table, table_name) / sizeof(uint16_t)) 41 | 42 | typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES_V2_1 { 43 | uint16_t utilitypipeline; /* Offest for the utility to get parser info,Don't change this position!*/ 44 | uint16_t multimedia_info; 45 | uint16_t smc_dpm_info; 46 | uint16_t sw_datatable3; 47 | uint16_t firmwareinfo; /* Shared by various SW components */ 48 | uint16_t sw_datatable5; 49 | uint16_t lcd_info; /* Shared by various SW components */ 50 | uint16_t sw_datatable7; 51 | uint16_t smu_info; 52 | uint16_t sw_datatable9; 53 | uint16_t sw_datatable10; 54 | uint16_t vram_usagebyfirmware; /* Shared by various SW components */ 55 | uint16_t gpio_pin_lut; /* Shared by various SW components */ 56 | uint16_t sw_datatable13; 57 | uint16_t gfx_info; 58 | uint16_t powerplayinfo; /* Shared by various SW components */ 59 | uint16_t sw_datatable16; 60 | uint16_t sw_datatable17; 61 | uint16_t sw_datatable18; 62 | uint16_t sw_datatable19; 63 | uint16_t sw_datatable20; 64 | uint16_t sw_datatable21; 65 | uint16_t displayobjectinfo; /* Shared by various SW components */ 66 | uint16_t indirectioaccess; /* used as an internal one */ 67 | uint16_t umc_info; /* Shared by various SW components */ 68 | uint16_t sw_datatable25; 69 | uint16_t sw_datatable26; 70 | uint16_t dce_info; /* Shared by various SW components */ 71 | uint16_t vram_info; /* Shared by various SW components */ 72 | uint16_t sw_datatable29; 73 | uint16_t integratedsysteminfo; /* Shared by various SW components */ 74 | uint16_t asic_profiling_info; /* Shared by various SW components */ 75 | uint16_t voltageobject_info; /* shared by various SW components */ 76 | uint16_t sw_datatable33; 77 | uint16_t sw_datatable34; 78 | } ATOM_MASTER_LIST_OF_DATA_TABLES_V2_1; 79 | 80 | typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES { 81 | uint16_t UtilityPipeLine; // Offest for the utility to get parser info,Don't change this position! 82 | uint16_t MultimediaCapabilityInfo; // Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios 83 | uint16_t MultimediaConfigInfo; // Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios 84 | uint16_t StandardVESA_Timing; // Only used by Bios 85 | uint16_t FirmwareInfo; // Shared by various SW components,latest version 1.4 86 | uint16_t PaletteData; // Only used by BIOS 87 | uint16_t LCD_Info; // Shared by various SW components,latest version 1.3, was called LVDS_Info 88 | uint16_t DIGTransmitterInfo; // Internal used by VBIOS only version 3.1 89 | uint16_t SMU_Info; // Shared by various SW components,latest version 1.1 90 | uint16_t SupportedDevicesInfo; // Will be obsolete from R600 91 | uint16_t GPIO_I2C_Info; // Shared by various SW components,latest version 1.2 will be used from R600 92 | uint16_t VRAM_UsageByFirmware; // Shared by various SW components,latest version 1.3 will be used from R600 93 | uint16_t GPIO_Pin_LUT; // Shared by various SW components,latest version 1.1 94 | uint16_t VESA_ToInternalModeLUT; // Only used by Bios 95 | uint16_t GFX_Info; // Shared by various SW components,latest version 2.1 will be used from R600 96 | uint16_t PowerPlayInfo; // Shared by various SW components,latest version 2.1,new design from R600 97 | uint16_t GPUVirtualizationInfo; // Will be obsolete from R600 98 | uint16_t SaveRestoreInfo; // Only used by Bios 99 | uint16_t PPLL_SS_Info; // Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info 100 | uint16_t OemInfo; // Defined and used by external SW, should be obsolete soon 101 | uint16_t XTMDS_Info; // Will be obsolete from R600 102 | uint16_t MclkSS_Info; // Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used 103 | uint16_t Object_Header; // Shared by various SW components,latest version 1.1 104 | uint16_t IndirectIOAccess; // Only used by Bios,this table position can't change at all!! 105 | uint16_t MC_InitParameter; // Only used by command table 106 | uint16_t ASIC_VDDC_Info; // Will be obsolete from R600 107 | uint16_t ASIC_InternalSS_Info; // New tabel name from R600, used to be called "ASIC_MVDDC_Info" 108 | uint16_t TV_VideoMode; // Only used by command table 109 | uint16_t VRAM_Info; // Only used by command table, latest version 1.3 110 | uint16_t MemoryTrainingInfo; // Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1 111 | uint16_t IntegratedSystemInfo; // Shared by various SW components 112 | uint16_t ASIC_ProfilingInfo; // New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600 113 | uint16_t VoltageObjectInfo; // Shared by various SW components, latest version 1.1 114 | uint16_t PowerSourceInfo; // Shared by various SW components, latest versoin 1.1 115 | uint16_t ServiceInfo; 116 | } ATOM_MASTER_LIST_OF_DATA_TABLES; 117 | 118 | typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES { 119 | uint16_t ASIC_Init; //Function Table, used by various SW components,latest version 1.1 120 | uint16_t GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON 121 | uint16_t ASIC_RegistersInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init 122 | uint16_t VRAM_BlockVenderDetection; //Atomic Table, used only by Bios 123 | uint16_t DIGxEncoderControl; //Only used by Bios 124 | uint16_t MemoryControllerInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init 125 | uint16_t EnableCRTCMemReq; //Function Table,directly used by various SW components,latest version 2.1 126 | uint16_t MemoryParamAdjust; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed 127 | uint16_t DVOEncoderControl; //Function Table,directly used by various SW components,latest version 1.2 128 | uint16_t GPIOPinControl; //Atomic Table, only used by Bios 129 | uint16_t SetEngineClock; //Function Table,directly used by various SW components,latest version 1.1 130 | uint16_t SetMemoryClock; //Function Table,directly used by various SW components,latest version 1.1 131 | uint16_t SetPixelClock; //Function Table,directly used by various SW components,latest version 1.2 132 | uint16_t EnableDispPowerGating; //Atomic Table, indirectly used by various SW components,called from ASIC_Init 133 | uint16_t ResetMemoryDLL; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 134 | uint16_t ResetMemoryDevice; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 135 | uint16_t MemoryPLLInit; //Atomic Table, used only by Bios 136 | uint16_t AdjustDisplayPll; //Atomic Table, used by various SW componentes. 137 | uint16_t AdjustMemoryController; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 138 | uint16_t EnableASIC_StaticPwrMgt; //Atomic Table, only used by Bios 139 | uint16_t SetUniphyInstance; //Atomic Table, only used by Bios 140 | uint16_t DAC_LoadDetection; //Atomic Table, directly used by various SW components,latest version 1.2 141 | uint16_t LVTMAEncoderControl; //Atomic Table,directly used by various SW components,latest version 1.3 142 | uint16_t HW_Misc_Operation; //Atomic Table, directly used by various SW components,latest version 1.1 143 | uint16_t DAC1EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 144 | uint16_t DAC2EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 145 | uint16_t DVOOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 146 | uint16_t CV1OutputControl; //Atomic Table, Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead 147 | uint16_t GetConditionalGoldenSetting; //Only used by Bios 148 | uint16_t SMC_Init; //Function Table,directly used by various SW components,latest version 1.1 149 | uint16_t PatchMCSetting; //only used by BIOS 150 | uint16_t MC_SEQ_Control; //only used by BIOS 151 | uint16_t Gfx_Harvesting; //Atomic Table, Obsolete from Ry6xx, Now only used by BIOS for GFX harvesting 152 | uint16_t EnableScaler; //Atomic Table, used only by Bios 153 | uint16_t BlankCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 154 | uint16_t EnableCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 155 | uint16_t GetPixelClock; //Atomic Table, directly used by various SW components,latest version 1.1 156 | uint16_t EnableVGA_Render; //Function Table,directly used by various SW components,latest version 1.1 157 | uint16_t GetSCLKOverMCLKRatio; //Atomic Table, only used by Bios 158 | uint16_t SetCRTC_Timing; //Atomic Table, directly used by various SW components,latest version 1.1 159 | uint16_t SetCRTC_OverScan; //Atomic Table, used by various SW components,latest version 1.1 160 | uint16_t GetSMUClockInfo; //Atomic Table, used only by Bios 161 | uint16_t SelectCRTC_Source; //Atomic Table, directly used by various SW components,latest version 1.1 162 | uint16_t EnableGraphSurfaces; //Atomic Table, used only by Bios 163 | uint16_t UpdateCRTC_DoubleBufferRegisters; //Atomic Table, used only by Bios 164 | uint16_t LUT_AutoFill; //Atomic Table, only used by Bios 165 | uint16_t SetDCEClock; //Atomic Table, start from DCE11.1, shared by driver and VBIOS, change DISPCLK and DPREFCLK 166 | uint16_t GetMemoryClock; //Atomic Table, directly used by various SW components,latest version 1.1 167 | uint16_t GetEngineClock; //Atomic Table, directly used by various SW components,latest version 1.1 168 | uint16_t SetCRTC_UsingDTDTiming; //Atomic Table, directly used by various SW components,latest version 1.1 169 | uint16_t ExternalEncoderControl; //Atomic Table, directly used by various SW components,latest version 2.1 170 | uint16_t LVTMAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 171 | uint16_t VRAM_BlockDetectionByStrap; //Atomic Table, used only by Bios 172 | uint16_t MemoryCleanUp; //Atomic Table, only used by Bios 173 | uint16_t ProcessI2cChannelTransaction; //Function Table,only used by Bios 174 | uint16_t WriteOneByteToHWAssistedI2C; //Function Table,indirectly used by various SW components 175 | uint16_t ReadHWAssistedI2CStatus; //Atomic Table, indirectly used by various SW components 176 | uint16_t SpeedFanControl; //Function Table,indirectly used by various SW components,called from ASIC_Init 177 | uint16_t PowerConnectorDetection; //Atomic Table, directly used by various SW components,latest version 1.1 178 | uint16_t MC_Synchronization; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 179 | uint16_t ComputeMemoryEnginePLL; //Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock 180 | uint16_t Gfx_Init; //Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock 181 | uint16_t VRAM_GetCurrentInfoBlock; //Atomic Table, used only by Bios 182 | uint16_t DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 183 | uint16_t MemoryTraining; //Atomic Table, used only by Bios 184 | uint16_t EnableSpreadSpectrumOnPPLL; //Atomic Table, directly used by various SW components,latest version 1.2 185 | uint16_t TMDSAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 186 | uint16_t SetVoltage; //Function Table,directly and/or indirectly used by various SW components,latest version 1.1 187 | uint16_t DAC1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 188 | uint16_t ReadEfuseValue; //Atomic Table, directly used by various SW components,latest version 1.1 189 | uint16_t ComputeMemoryClockParam; //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C" 190 | uint16_t ClockSource; //Atomic Table, indirectly used by various SW components,called from ASIC_Init 191 | uint16_t MemoryDeviceInit; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 192 | uint16_t GetDispObjectInfo; //Atomic Table, indirectly used by various SW components,called from EnableVGARender 193 | uint16_t DIG1EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 194 | uint16_t DIG2EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 195 | uint16_t DIG1TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 196 | uint16_t DIG2TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 197 | uint16_t ProcessAuxChannelTransaction; //Function Table,only used by Bios 198 | uint16_t DPEncoderService; //Function Table,only used by Bios 199 | uint16_t GetVoltageInfo; //Function Table,only used by Bios since SI 200 | } ATOM_MASTER_LIST_OF_COMMAND_TABLES; 201 | 202 | typedef struct _ATOM_COMMON_TABLE_HEADER { 203 | uint16_t usStructureSize; 204 | uint8_t ucTableFormatRevision; //Change it when the Parser is not backward compatible 205 | uint8_t ucTableContentRevision; //Change it only when the table needs to change but the firmware 206 | //Image can't be updated, while Driver needs to carry the new table! 207 | } ATOM_COMMON_TABLE_HEADER; 208 | 209 | typedef struct _ATOM_OBJECT_HEADER 210 | { 211 | ATOM_COMMON_TABLE_HEADER sHeader; 212 | uint16_t usDeviceSupport; 213 | uint16_t usConnectorObjectTableOffset; 214 | uint16_t usRouterObjectTableOffset; 215 | uint16_t usEncoderObjectTableOffset; 216 | uint16_t usProtectionObjectTableOffset; //only available when Protection block is independent. 217 | uint16_t usDisplayPathTableOffset; 218 | }ATOM_OBJECT_HEADER; 219 | 220 | typedef struct _ATOM_I2C_ID_CONFIG { 221 | #if defined(__BIG_ENDIAN) 222 | uint8_t bfHW_Capable:1; 223 | uint8_t bfHW_EngineID:3; 224 | uint8_t bfI2C_LineMux:4; 225 | #else 226 | uint8_t bfI2C_LineMux:4; 227 | uint8_t bfHW_EngineID:3; 228 | uint8_t bfHW_Capable:1; 229 | #endif 230 | } ATOM_I2C_ID_CONFIG; 231 | 232 | typedef union _ATOM_I2C_ID_CONFIG_ACCESS { 233 | ATOM_I2C_ID_CONFIG sbfAccess; 234 | uint8_t ucAccess; 235 | } ATOM_I2C_ID_CONFIG_ACCESS; 236 | 237 | typedef struct _ATOM_GPIO_I2C_ASSIGMENT { 238 | uint16_t usClkMaskRegisterIndex; 239 | uint16_t usClkEnRegisterIndex; 240 | uint16_t usClkY_RegisterIndex; 241 | uint16_t usClkA_RegisterIndex; 242 | uint16_t usDataMaskRegisterIndex; 243 | uint16_t usDataEnRegisterIndex; 244 | uint16_t usDataY_RegisterIndex; 245 | uint16_t usDataA_RegisterIndex; 246 | ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; 247 | uint8_t ucClkMaskShift; 248 | uint8_t ucClkEnShift; 249 | uint8_t ucClkY_Shift; 250 | uint8_t ucClkA_Shift; 251 | uint8_t ucDataMaskShift; 252 | uint8_t ucDataEnShift; 253 | uint8_t ucDataY_Shift; 254 | uint8_t ucDataA_Shift; 255 | uint8_t ucReserved1; 256 | uint8_t ucReserved2; 257 | } ATOM_GPIO_I2C_ASSIGMENT; 258 | 259 | typedef struct _ATOM_GPIO_I2C_INFO { 260 | ATOM_COMMON_TABLE_HEADER sHeader; 261 | ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE]; 262 | } ATOM_GPIO_I2C_INFO; 263 | 264 | typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO { 265 | uint32_t ulStartAddrUsedByFirmware; 266 | uint16_t usFirmwareUseInKb; 267 | uint16_t usReserved; 268 | } ATOM_FIRMWARE_VRAM_RESERVE_INFO; 269 | 270 | typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE { 271 | ATOM_COMMON_TABLE_HEADER sHeader; 272 | ATOM_FIRMWARE_VRAM_RESERVE_INFO asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO]; 273 | } ATOM_VRAM_USAGE_BY_FIRMWARE; 274 | 275 | typedef struct _VRAM_USAGEBYFIRMWARE_V2_1 { 276 | ATOM_COMMON_TABLE_HEADER table_header; 277 | uint32_t start_address_in_kb; 278 | uint16_t used_by_firmware_in_kb; 279 | uint16_t used_by_driver_in_kb; 280 | } VRAM_USAGEBYFIRMWARE_V2_1; 281 | 282 | typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS { 283 | uint8_t ucI2CSpeed; 284 | union 285 | { 286 | uint8_t ucRegIndex; 287 | uint8_t ucStatus; 288 | }; 289 | uint16_t lpI2CDataOut; 290 | uint8_t ucFlag; 291 | uint8_t ucTransBytes; 292 | uint8_t ucSlaveAddr; 293 | uint8_t ucLineNumber; 294 | } PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS; 295 | 296 | typedef struct _ATOM_FIRMWARE_INFO_V3_1 { 297 | ATOM_COMMON_TABLE_HEADER table_header; 298 | uint32_t firmware_revision; 299 | uint32_t bootup_sclk_in10khz; 300 | uint32_t bootup_mclk_in10khz; 301 | uint32_t firmware_capability; // enum atombios_firmware_capability 302 | uint32_t main_call_parser_entry; /* direct address of main parser call in VBIOS binary. */ 303 | uint32_t bios_scratch_reg_startaddr; // 1st bios scratch register dword address 304 | uint16_t bootup_vddc_mv; 305 | uint16_t bootup_vddci_mv; 306 | uint16_t bootup_mvddc_mv; 307 | uint16_t bootup_vddgfx_mv; 308 | uint8_t mem_module_id; 309 | uint8_t coolingsolution_id; /*0: Air cooling; 1: Liquid cooling ... */ 310 | uint8_t reserved1[2]; 311 | uint32_t mc_baseaddr_high; 312 | uint32_t mc_baseaddr_low; 313 | uint32_t reserved2[6]; 314 | } ATOM_FIRMWARE_INFO_V3_1; 315 | 316 | typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS { 317 | uint16_t lpAuxRequest; 318 | uint16_t lpDataOut; 319 | uint8_t ucChannelID; 320 | union { 321 | uint8_t ucReplyStatus; 322 | uint8_t ucDelay; 323 | }; 324 | uint8_t ucDataOutLen; 325 | uint8_t ucReserved; 326 | } PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS; 327 | 328 | typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 { 329 | uint16_t lpAuxRequest; 330 | uint16_t lpDataOut; 331 | uint8_t ucChannelID; 332 | union { 333 | uint8_t ucReplyStatus; 334 | uint8_t ucDelay; 335 | }; 336 | uint8_t ucDataOutLen; 337 | uint8_t ucHPD_ID; //=0: HPD1, =1: HPD2, =2: HPD3, =3: HPD4, =4: HPD5, =5: HPD6 338 | } PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2; 339 | 340 | #define PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS 341 | 342 | #endif 343 | -------------------------------------------------------------------------------- /aura-gpu-bios.h: -------------------------------------------------------------------------------- 1 | #ifndef _UAPI_AURA_GPU_BIOS_H 2 | #define _UAPI_AURA_GPU_BIOS_H 3 | 4 | #include 5 | #include "include/types.h" 6 | 7 | struct atom_bios { 8 | char name[20]; 9 | size_t size; // TODO 10 | const char* data; 11 | }; 12 | 13 | struct gpio_info { 14 | uint32_t clk_mask_register_index; 15 | uint32_t clk_en_register_index; 16 | uint32_t clk_y_register_index; 17 | uint32_t clk_a_register_index; 18 | uint32_t data_mask_register_index; 19 | uint32_t data_en_register_index; 20 | uint32_t data_y_register_index; 21 | uint32_t data_a_register_index; 22 | 23 | uint8_t clk_mask_shift; 24 | uint8_t clk_en_shift; 25 | uint8_t clk_y_shift; 26 | uint8_t clk_a_shift; 27 | uint8_t data_mask_shift; 28 | uint8_t data_en_shift; 29 | uint8_t data_y_shift; 30 | uint8_t data_a_shift; 31 | 32 | uint32_t clk_mask_mask; 33 | uint32_t clk_en_mask; 34 | uint32_t clk_y_mask; 35 | uint32_t clk_a_mask; 36 | uint32_t data_mask_mask; 37 | uint32_t data_en_mask; 38 | uint32_t data_y_mask; 39 | uint32_t data_a_mask; 40 | }; 41 | 42 | struct i2c_info { 43 | struct gpio_info gpio_info; 44 | 45 | bool hw_assist; 46 | 47 | uint32_t line; 48 | uint32_t engine_id; 49 | uint32_t slave_address; 50 | }; 51 | 52 | // #define aura_i2c_info graphics_object_i2c_info 53 | 54 | struct gpio_pin_info { 55 | uint32_t offset; 56 | uint32_t offset_y; 57 | uint32_t offset_en; 58 | uint32_t offset_mask; 59 | 60 | uint32_t mask; 61 | uint32_t mask_y; 62 | uint32_t mask_en; 63 | uint32_t mask_mask; 64 | }; 65 | 66 | struct graphics_object_id { 67 | uint32_t id:8; 68 | uint32_t enum_id:4; 69 | uint32_t type:4; 70 | uint32_t reserved:16; /* for padding. total size should be u32 */ 71 | }; 72 | 73 | error_t 74 | atom_bios_get_gpio_info (struct atom_bios *bios, uint8_t index, struct i2c_info *info); 75 | 76 | uint8_t 77 | atom_bios_get_connectors_number (struct atom_bios *bios); 78 | 79 | bool 80 | atom_bios_get_connector_id (struct atom_bios *bios, uint8_t index, struct graphics_object_id *object_id); 81 | 82 | error_t 83 | atom_bios_get_i2c_info (struct atom_bios *bios, struct graphics_object_id *object_id, struct i2c_info *info); 84 | 85 | error_t 86 | atom_bios_get_crystal_frequency (struct atom_bios* bios, uint32_t *frequency); 87 | 88 | struct atom_bios* 89 | atom_bios_create (struct pci_dev *pci_dev); 90 | 91 | void 92 | atom_bios_release (struct atom_bios* bios); 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /aura-gpu-hw.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | #include 3 | 4 | #include "debug.h" 5 | #include "pci_ids.h" 6 | #include "aura-gpu-hw.h" 7 | #include "aura-gpu-bios.h" 8 | #include "aura-gpu-reg.h" 9 | #include "atom/atom.h" 10 | 11 | struct ATOM_MASTER_LIST_OF_COMMAND_TABLES { 12 | uint16_t ASIC_Init; //Function Table, used by various SW components,latest version 1.1 13 | uint16_t GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON 14 | uint16_t ASIC_RegistersInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init 15 | uint16_t VRAM_BlockVenderDetection; //Atomic Table, used only by Bios 16 | uint16_t DIGxEncoderControl; //Only used by Bios 17 | uint16_t MemoryControllerInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init 18 | uint16_t EnableCRTCMemReq; //Function Table,directly used by various SW components,latest version 2.1 19 | uint16_t MemoryParamAdjust; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed 20 | uint16_t DVOEncoderControl; //Function Table,directly used by various SW components,latest version 1.2 21 | uint16_t GPIOPinControl; //Atomic Table, only used by Bios 22 | uint16_t SetEngineClock; //Function Table,directly used by various SW components,latest version 1.1 23 | uint16_t SetMemoryClock; //Function Table,directly used by various SW components,latest version 1.1 24 | uint16_t SetPixelClock; //Function Table,directly used by various SW components,latest version 1.2 25 | uint16_t EnableDispPowerGating; //Atomic Table, indirectly used by various SW components,called from ASIC_Init 26 | uint16_t ResetMemoryDLL; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 27 | uint16_t ResetMemoryDevice; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 28 | uint16_t MemoryPLLInit; //Atomic Table, used only by Bios 29 | uint16_t AdjustDisplayPll; //Atomic Table, used by various SW componentes. 30 | uint16_t AdjustMemoryController; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 31 | uint16_t EnableASIC_StaticPwrMgt; //Atomic Table, only used by Bios 32 | uint16_t SetUniphyInstance; //Atomic Table, only used by Bios 33 | uint16_t DAC_LoadDetection; //Atomic Table, directly used by various SW components,latest version 1.2 34 | uint16_t LVTMAEncoderControl; //Atomic Table,directly used by various SW components,latest version 1.3 35 | uint16_t HW_Misc_Operation; //Atomic Table, directly used by various SW components,latest version 1.1 36 | uint16_t DAC1EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 37 | uint16_t DAC2EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 38 | uint16_t DVOOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 39 | uint16_t CV1OutputControl; //Atomic Table, Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead 40 | uint16_t GetConditionalGoldenSetting; //Only used by Bios 41 | uint16_t SMC_Init; //Function Table,directly used by various SW components,latest version 1.1 42 | uint16_t PatchMCSetting; //only used by BIOS 43 | uint16_t MC_SEQ_Control; //only used by BIOS 44 | uint16_t Gfx_Harvesting; //Atomic Table, Obsolete from Ry6xx, Now only used by BIOS for GFX harvesting 45 | uint16_t EnableScaler; //Atomic Table, used only by Bios 46 | uint16_t BlankCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 47 | uint16_t EnableCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 48 | uint16_t GetPixelClock; //Atomic Table, directly used by various SW components,latest version 1.1 49 | uint16_t EnableVGA_Render; //Function Table,directly used by various SW components,latest version 1.1 50 | uint16_t GetSCLKOverMCLKRatio; //Atomic Table, only used by Bios 51 | uint16_t SetCRTC_Timing; //Atomic Table, directly used by various SW components,latest version 1.1 52 | uint16_t SetCRTC_OverScan; //Atomic Table, used by various SW components,latest version 1.1 53 | uint16_t GetSMUClockInfo; //Atomic Table, used only by Bios 54 | uint16_t SelectCRTC_Source; //Atomic Table, directly used by various SW components,latest version 1.1 55 | uint16_t EnableGraphSurfaces; //Atomic Table, used only by Bios 56 | uint16_t UpdateCRTC_DoubleBufferRegisters; //Atomic Table, used only by Bios 57 | uint16_t LUT_AutoFill; //Atomic Table, only used by Bios 58 | uint16_t SetDCEClock; //Atomic Table, start from DCE11.1, shared by driver and VBIOS, change DISPCLK and DPREFCLK 59 | uint16_t GetMemoryClock; //Atomic Table, directly used by various SW components,latest version 1.1 60 | uint16_t GetEngineClock; //Atomic Table, directly used by various SW components,latest version 1.1 61 | uint16_t SetCRTC_UsingDTDTiming; //Atomic Table, directly used by various SW components,latest version 1.1 62 | uint16_t ExternalEncoderControl; //Atomic Table, directly used by various SW components,latest version 2.1 63 | uint16_t LVTMAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 64 | uint16_t VRAM_BlockDetectionByStrap; //Atomic Table, used only by Bios 65 | uint16_t MemoryCleanUp; //Atomic Table, only used by Bios 66 | uint16_t ProcessI2cChannelTransaction; //Function Table,only used by Bios 67 | uint16_t WriteOneByteToHWAssistedI2C; //Function Table,indirectly used by various SW components 68 | uint16_t ReadHWAssistedI2CStatus; //Atomic Table, indirectly used by various SW components 69 | uint16_t SpeedFanControl; //Function Table,indirectly used by various SW components,called from ASIC_Init 70 | uint16_t PowerConnectorDetection; //Atomic Table, directly used by various SW components,latest version 1.1 71 | uint16_t MC_Synchronization; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 72 | uint16_t ComputeMemoryEnginePLL; //Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock 73 | uint16_t Gfx_Init; //Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock 74 | uint16_t VRAM_GetCurrentInfoBlock; //Atomic Table, used only by Bios 75 | uint16_t DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 76 | uint16_t MemoryTraining; //Atomic Table, used only by Bios 77 | uint16_t EnableSpreadSpectrumOnPPLL; //Atomic Table, directly used by various SW components,latest version 1.2 78 | uint16_t TMDSAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 79 | uint16_t SetVoltage; //Function Table,directly and/or indirectly used by various SW components,latest version 1.1 80 | uint16_t DAC1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 81 | uint16_t ReadEfuseValue; //Atomic Table, directly used by various SW components,latest version 1.1 82 | uint16_t ComputeMemoryClockParam; //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C" 83 | uint16_t ClockSource; //Atomic Table, indirectly used by various SW components,called from ASIC_Init 84 | uint16_t MemoryDeviceInit; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock 85 | uint16_t GetDispObjectInfo; //Atomic Table, indirectly used by various SW components,called from EnableVGARender 86 | uint16_t DIG1EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 87 | uint16_t DIG2EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 88 | uint16_t DIG1TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 89 | uint16_t DIG2TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 90 | uint16_t ProcessAuxChannelTransaction; //Function Table,only used by Bios 91 | uint16_t DPEncoderService; //Function Table,only used by Bios 92 | uint16_t GetVoltageInfo; //Function Table,only used by Bios since SI 93 | }; 94 | 95 | #define GetIndexIntoMasterTable(MasterOrData, FieldName) ( \ 96 | (((char*)(&((struct ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES*)0)->FieldName)-(char*)0)/sizeof(uint16_t)) \ 97 | ) 98 | 99 | struct hw_i2c_context { 100 | struct card_info atom_card_info; 101 | struct atom_context *atom_context; 102 | struct aura_reg_service *reg_service; 103 | struct atom_bios *bios; 104 | struct i2c_adapter adapter; 105 | bool registered; 106 | 107 | uint8_t scratch[20 * 1024]; 108 | }; 109 | #define context_from_adapter(ptr) ( \ 110 | container_of(ptr, struct hw_i2c_context, adapter) \ 111 | ) 112 | #define context_from_card(ptr) ( \ 113 | container_of(ptr, struct hw_i2c_context, atom_card_info) \ 114 | ) 115 | 116 | static uint32_t __invalid_read ( 117 | struct card_info *info, 118 | uint32_t reg 119 | ){ 120 | AURA_DBG("non MM read called"); 121 | return 0; 122 | } 123 | 124 | static void __invalid_write ( 125 | struct card_info *info, 126 | uint32_t reg, 127 | uint32_t val 128 | ){ 129 | AURA_DBG("non MM write called"); 130 | } 131 | 132 | static uint32_t mm_read ( 133 | struct card_info *info, 134 | uint32_t reg 135 | ){ 136 | uint32_t res; 137 | struct hw_i2c_context *ctx = context_from_card(info); 138 | 139 | res = reg_read(ctx->reg_service, reg); 140 | AURA_DBG("Read reg %x %x", reg, res); 141 | 142 | return res; 143 | } 144 | 145 | static void mm_write ( 146 | struct card_info *info, 147 | uint32_t reg, 148 | uint32_t val 149 | ){ 150 | struct hw_i2c_context *ctx = context_from_card(info); 151 | 152 | AURA_DBG("Writing reg %x val %x", reg, val); 153 | reg_write(ctx->reg_service, reg, val); 154 | } 155 | 156 | #define TARGET_HW_I2C_CLOCK 50 157 | #define ATOM_MAX_HW_I2C_WRITE 3 158 | #define ATOM_MAX_HW_I2C_READ 255 159 | #define HW_I2C_WRITE 1 160 | #define HW_I2C_READ 0 161 | #define HW_ASSISTED_I2C_STATUS_FAILURE 2 162 | #define HW_ASSISTED_I2C_STATUS_SUCCESS 1 163 | 164 | struct transaction_parameters { 165 | uint8_t ucI2CSpeed; 166 | union { 167 | uint8_t ucRegIndex; 168 | uint8_t ucStatus; 169 | }; 170 | uint16_t lpI2CDataOut; 171 | uint8_t ucFlag; 172 | uint8_t ucTransBytes; 173 | uint8_t ucSlaveAddr; 174 | uint8_t ucLineNumber; 175 | }; 176 | 177 | static error_t aura_gpu_i2c_process_i2c_ch( 178 | struct hw_i2c_context *context, 179 | uint8_t slave_addr, 180 | uint8_t offset, 181 | uint8_t flags, 182 | uint8_t *buf 183 | ){ 184 | struct transaction_parameters args; 185 | int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction); 186 | error_t err = 0; 187 | 188 | memset(&args, 0, sizeof(args)); 189 | 190 | if (flags & HW_I2C_WRITE) { 191 | args.lpI2CDataOut = buf ? cpu_to_le16(*buf) : 0; 192 | } else if (!buf) { 193 | err = -EINVAL; 194 | goto done; 195 | } else { 196 | args.lpI2CDataOut = 0; 197 | } 198 | 199 | args.ucFlag = flags; 200 | args.ucI2CSpeed = TARGET_HW_I2C_CLOCK; 201 | args.ucTransBytes = 1; 202 | args.ucSlaveAddr = slave_addr << 1; 203 | args.ucRegIndex = offset; 204 | args.ucLineNumber = 6; 205 | 206 | AURA_DBG("Pre Transaction: addr = %x, offset = %x, rw = %s, count = %d, out = %x", 207 | args.ucSlaveAddr >> 1, 208 | offset, 209 | args.ucFlag == HW_I2C_READ ? "r" : "w", 210 | args.ucTransBytes, 211 | args.lpI2CDataOut 212 | ); 213 | 214 | atom_execute_table(context->atom_context, index, (uint32_t *)&args); 215 | 216 | AURA_DBG( 217 | "Post Transaction: status = %x, read = %x", 218 | args.ucStatus, 219 | args.lpI2CDataOut 220 | ); 221 | 222 | /* error */ 223 | if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) { 224 | AURA_DBG("hw_i2c error %x", args.ucStatus); 225 | err = -EIO; 226 | goto done; 227 | } 228 | 229 | if (!(flags & HW_I2C_WRITE)) { 230 | *buf = (uint8_t)args.lpI2CDataOut; 231 | } 232 | 233 | done: 234 | return err; 235 | } 236 | 237 | #define dump_i2c_msg(num, msg) ({ \ 238 | AURA_DBG( \ 239 | "Message %d addr = %x, len = %d, flags = %x, data = %x %x", \ 240 | (num), \ 241 | (msg).addr, \ 242 | (msg).len, \ 243 | (msg).flags, \ 244 | (msg).buf[0], \ 245 | (msg).buf[1] \ 246 | ); \ 247 | }) 248 | 249 | static int aura_gpu_i2c_xfer( 250 | struct i2c_adapter *i2c_adap, 251 | struct i2c_msg *msgs, 252 | int num 253 | ){ 254 | struct hw_i2c_context *context = i2c_get_adapdata(i2c_adap); 255 | int remaining, buffer_offset; 256 | uint8_t flags; 257 | uint8_t offset; 258 | uint8_t address; 259 | error_t err; 260 | int i; 261 | 262 | /* check for bus probe */ 263 | if ((num == 1) && (msgs[0].len == 0)) { 264 | if (msgs[0].len == 0) { 265 | // AURA_DBG("Bus probe detected %x", msgs[0].addr); 266 | err = aura_gpu_i2c_process_i2c_ch( 267 | context, 268 | msgs[0].addr, 269 | 0, 270 | HW_I2C_WRITE, 271 | NULL 272 | ); 273 | } 274 | 275 | return err ? err : num; 276 | } else if ((num == 1) && (msgs[0].len > 1) && !(msgs[0].flags & I2C_M_RD)) { 277 | // The first data byte should be the offset, remainder are the values 278 | offset = msgs[0].buf[0]; 279 | address = msgs[0].addr; 280 | remaining = msgs[0].len - 1; 281 | buffer_offset = 1; 282 | 283 | while (remaining) { 284 | err = aura_gpu_i2c_process_i2c_ch( 285 | context, 286 | address, 287 | offset, 288 | HW_I2C_WRITE, 289 | &msgs[0].buf[buffer_offset] 290 | ); 291 | 292 | if (err) 293 | return err; 294 | 295 | offset++; 296 | remaining--; 297 | buffer_offset++; 298 | } 299 | } else if (num == 2) { 300 | // The first message should be to set the offset 301 | if (!(msgs[0].flags & I2C_M_RD) && msgs[0].len == 1) { 302 | offset = msgs[0].buf[0]; 303 | address = msgs[0].addr; 304 | } else { 305 | return -EIO; 306 | } 307 | 308 | // The second message should describe how many bytes to read/write 309 | remaining = msgs[1].len; 310 | buffer_offset = 0; 311 | flags = (msgs[1].flags & I2C_M_RD) ? HW_I2C_READ : HW_I2C_WRITE; 312 | 313 | while (remaining) { 314 | err = aura_gpu_i2c_process_i2c_ch( 315 | context, 316 | address, 317 | offset, 318 | flags, 319 | &msgs[1].buf[buffer_offset] 320 | ); 321 | 322 | if (err) 323 | return err; 324 | 325 | offset++; 326 | remaining--; 327 | buffer_offset++; 328 | } 329 | } else { 330 | AURA_DBG("Failed to process messages"); 331 | for (i = 0; i < num; i++) 332 | dump_i2c_msg(i, msgs[i]); 333 | 334 | return -EIO; 335 | } 336 | 337 | return num; 338 | } 339 | 340 | static uint32_t aura_gpu_i2c_func( 341 | struct i2c_adapter *adap 342 | ){ 343 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 344 | } 345 | 346 | static const struct i2c_algorithm aura_gpu_i2c_algo = { 347 | .master_xfer = aura_gpu_i2c_xfer, 348 | .functionality = aura_gpu_i2c_func, 349 | }; 350 | 351 | 352 | static void aura_gpu_i2c_destroy ( 353 | struct hw_i2c_context *context 354 | ){ 355 | if (context->bios) 356 | atom_bios_release(context->bios); 357 | 358 | if (context->reg_service) 359 | aura_gpu_reg_destroy(context->reg_service); 360 | 361 | if (context->atom_context) 362 | atom_destroy(context->atom_context); 363 | 364 | if (context->registered) { 365 | i2c_set_adapdata(&context->adapter, NULL); 366 | i2c_del_adapter(&context->adapter); 367 | } 368 | 369 | kfree(context); 370 | } 371 | 372 | static struct hw_i2c_context *aura_gpu_i2c_create ( 373 | struct pci_dev *pci_dev 374 | ){ 375 | error_t err; 376 | struct hw_i2c_context *context = kzalloc(sizeof(*context), GFP_KERNEL); 377 | 378 | if (!context) 379 | return ERR_PTR(-ENOMEM); 380 | 381 | context->bios = atom_bios_create(pci_dev); 382 | if (IS_ERR_OR_NULL(context->bios)) { 383 | err = CLEAR_ERR(context->bios); 384 | goto error_free_all; 385 | } 386 | 387 | context->reg_service = aura_gpu_reg_create(pci_dev); 388 | if (IS_ERR_OR_NULL(context->reg_service)) { 389 | err = CLEAR_ERR(context->reg_service); 390 | goto error_free_all; 391 | } 392 | 393 | context->atom_card_info.reg_read = mm_read; 394 | context->atom_card_info.reg_write = mm_write; 395 | 396 | context->atom_card_info.ioreg_read = __invalid_read; 397 | context->atom_card_info.ioreg_write = __invalid_write; 398 | context->atom_card_info.mc_read = __invalid_read; 399 | context->atom_card_info.mc_write = __invalid_write; 400 | context->atom_card_info.pll_read = __invalid_read; 401 | context->atom_card_info.pll_write = __invalid_write; 402 | 403 | context->atom_context = atom_parse(&context->atom_card_info, context->bios->data); 404 | if (!context->atom_context) { 405 | kfree(context); 406 | return ERR_PTR(-ENOMEM); 407 | } 408 | 409 | mutex_init(&context->atom_context->mutex); 410 | context->atom_context->scratch = (uint32_t*)context->scratch; 411 | context->atom_context->scratch_size_bytes = sizeof(context->scratch); 412 | context->adapter.owner = THIS_MODULE; 413 | context->adapter.class = I2C_CLASS_DDC; 414 | 415 | i2c_set_adapdata(&context->adapter, context); 416 | 417 | snprintf(context->adapter.name, sizeof(context->adapter.name), "AURA GPU adapter"); 418 | context->adapter.algo = &aura_gpu_i2c_algo; 419 | 420 | err = i2c_add_adapter(&context->adapter); 421 | if (err) 422 | goto error_free_all; 423 | 424 | context->registered = true; 425 | 426 | return context; 427 | 428 | error_free_all: 429 | aura_gpu_i2c_destroy(context); 430 | 431 | return ERR_PTR(err); 432 | } 433 | 434 | static struct pci_dev *find_pci_dev ( 435 | void 436 | ){ 437 | struct pci_dev *pci_dev = NULL; 438 | const struct pci_device_id *match; 439 | 440 | while (NULL != (pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev))) { 441 | match = pci_match_id(pciidlist, pci_dev); 442 | if (match) 443 | return pci_dev; 444 | } 445 | 446 | return NULL; 447 | } 448 | 449 | struct i2c_adapter *aura_i2c_bios_create ( 450 | void 451 | ){ 452 | struct pci_dev *pci_dev = find_pci_dev(); 453 | struct hw_i2c_context *context; 454 | 455 | if (!pci_dev) { 456 | AURA_ERR("Failed to find a valid pci device"); 457 | return NULL; 458 | } 459 | 460 | context = aura_gpu_i2c_create(pci_dev); 461 | if (IS_ERR_OR_NULL(context)) 462 | return ERR_PTR(CLEAR_ERR(context)); 463 | 464 | return &context->adapter; 465 | } 466 | 467 | void aura_i2c_bios_destroy ( 468 | struct i2c_adapter *i2c_adapter 469 | ){ 470 | struct hw_i2c_context *context = context_from_adapter(i2c_adapter); 471 | 472 | if (IS_NULL(i2c_adapter)) 473 | return; 474 | 475 | aura_gpu_i2c_destroy(context); 476 | } 477 | -------------------------------------------------------------------------------- /aura-gpu-hw.h: -------------------------------------------------------------------------------- 1 | #ifndef _UAPI_AURA_GPU_HW_I2C_H 2 | #define _UAPI_AURA_GPU_HW_I2C_H 3 | 4 | #include 5 | 6 | struct i2c_adapter *aura_i2c_bios_create ( 7 | void 8 | ); 9 | 10 | void aura_i2c_bios_destroy ( 11 | struct i2c_adapter *i2c_adapter 12 | ); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /aura-gpu-i2c.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | #include 3 | #include 4 | 5 | #include "debug.h" 6 | #include "pci_ids.h" 7 | #include "aura-gpu-reg.h" 8 | #include "aura-gpu-i2c.h" 9 | #include "asic/asic-registers.h" 10 | 11 | enum { 12 | GPU_I2C_TIMEOUT_DELAY = 1000, 13 | GPU_I2C_TIMEOUT_INTERVAL = 10, 14 | }; 15 | 16 | enum aura_i2c_result { 17 | I2C_CHANNEL_OPERATION_SUCCEEDED, 18 | I2C_CHANNEL_OPERATION_FAILED, 19 | I2C_CHANNEL_OPERATION_NOT_GRANTED, 20 | I2C_CHANNEL_OPERATION_IS_BUSY, 21 | I2C_CHANNEL_OPERATION_NO_HANDLE_PROVIDED, 22 | I2C_CHANNEL_OPERATION_CHANNEL_IN_USE, 23 | I2C_CHANNEL_OPERATION_CHANNEL_CLIENT_MAX_ALLOWED, 24 | I2C_CHANNEL_OPERATION_ENGINE_BUSY, 25 | I2C_CHANNEL_OPERATION_TIMEOUT, 26 | I2C_CHANNEL_OPERATION_NO_RESPONSE, 27 | I2C_CHANNEL_OPERATION_HW_REQUEST_I2C_BUS, 28 | I2C_CHANNEL_OPERATION_WRONG_PARAMETER, 29 | I2C_CHANNEL_OPERATION_OUT_NB_OF_RETRIES, 30 | I2C_CHANNEL_OPERATION_NOT_STARTED 31 | }; 32 | 33 | enum aura_i2c_action { 34 | DCE_I2C_TRANSACTION_ACTION_I2C_WRITE = 0x00, 35 | DCE_I2C_TRANSACTION_ACTION_I2C_READ = 0x10, 36 | DCE_I2C_TRANSACTION_ACTION_I2C_STATUS_REQUEST = 0x20, 37 | 38 | DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT = 0x40, 39 | DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT = 0x50, 40 | DCE_I2C_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT = 0x60, 41 | 42 | DCE_I2C_TRANSACTION_ACTION_DP_WRITE = 0x80, 43 | DCE_I2C_TRANSACTION_ACTION_DP_READ = 0x90 44 | }; 45 | 46 | enum aura_i2c_status { 47 | DC_I2C_STATUS__DC_I2C_STATUS_IDLE, 48 | DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW, 49 | DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW, 50 | DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY = 2, 51 | }; 52 | 53 | struct aura_i2c_context { 54 | struct aura_reg_service *reg_service; 55 | enum aura_asic_type asic_type; 56 | 57 | uint32_t original_speed; 58 | uint32_t default_speed; 59 | 60 | uint32_t timeout_delay; 61 | uint32_t timeout_interval; 62 | 63 | const struct i2c_registers *registers; 64 | const struct i2c_shift *shifts; 65 | const struct i2c_mask *masks; 66 | 67 | struct i2c_adapter i2c_adapter; 68 | struct mutex mutex; 69 | }; 70 | 71 | #define context_from_adapter(ptr) ( \ 72 | container_of(ptr, struct aura_i2c_context, i2c_adapter) \ 73 | ) 74 | 75 | 76 | struct aura_i2c_payload { 77 | bool write; 78 | uint8_t address; 79 | uint32_t length; 80 | uint8_t *data; 81 | }; 82 | 83 | struct aura_i2c_transaction { 84 | enum aura_i2c_action action; 85 | enum aura_i2c_result status; 86 | uint8_t address; 87 | uint32_t length; 88 | uint8_t *data; 89 | }; 90 | 91 | 92 | static void clear_ack ( 93 | struct aura_i2c_context *context 94 | ){ 95 | struct aura_reg_service *reg = context->reg_service; 96 | 97 | reg_update_ex(reg, context->registers->GENERIC_I2C_INTERRUPT_CONTROL, (struct reg_fields[]){ 98 | /* 99 | Acknowledge bit for GENERIC_I2C_DONE. Write 1 to 100 | clear interrupt. 101 | */ 102 | PIN_FIELDS(context, GENERIC_I2C_DONE_ACK, 1), 103 | }, 1); 104 | } 105 | 106 | static error_t open_engine ( 107 | struct aura_i2c_context *context 108 | ){ 109 | struct aura_reg_service *reg; 110 | 111 | if (IS_NULL(context)) 112 | return -EINVAL; 113 | 114 | mutex_lock(&context->mutex); 115 | reg = context->reg_service; 116 | 117 | reg_update_ex(reg, context->registers->GENERIC_I2C_CONTROL, (struct reg_fields[]){ 118 | /* 119 | 120 | */ 121 | PIN_FIELDS(context, GENERIC_I2C_ENABLE, 1), 122 | }, 1); 123 | 124 | /* 125 | Read reg mmDCO_MEM_PWR_CTRL 6db6d800 126 | Writing reg mmDCO_MEM_PWR_CTRL 6db6d800 removing I2C_LIGHT_SLEEP_DIS && I2C_LIGHT_SLEEP_FORCE ?? 127 | Writing reg mmGLOBAL_CAPABILITIES 12260 128 | Read reg mmOUTPUT_PAYLOAD_CAPABILITY 0 129 | Writing reg mmOUTPUT_PAYLOAD_CAPABILITY 0 130 | Read reg mmOUTPUT_PAYLOAD_CAPABILITY 0 131 | Writing reg mmOUTPUT_PAYLOAD_CAPABILITY 0 132 | */ 133 | 134 | reg_update_ex(reg, context->registers->GENERIC_I2C_PIN_SELECTION, (struct reg_fields[]){ 135 | /* 136 | GPIO pin selection to use for SCL, if 137 | GENERIC_I2C_SCL_PIN_SEL == 138 | GENERIC_I2C_SDA_PIN_SEL => disable pin selectin. 139 | 140 | TODO: Where do these values come from and are they 141 | specific to asic types? 142 | */ 143 | PIN_FIELDS(context, GENERIC_I2C_SCL_PIN_SEL, 0x29), 144 | PIN_FIELDS(context, GENERIC_I2C_SDA_PIN_SEL, 0x28), 145 | }, 2); 146 | 147 | // set_speed(engine, 100); 148 | 149 | return 0; 150 | } 151 | 152 | static void close_engine ( 153 | struct aura_i2c_context *context 154 | ){ 155 | struct aura_reg_service *reg = context->reg_service; 156 | // struct reg_fields sw_status = PIN_FIELDS(engine, GENERIC_I2C_STATUS, 0); 157 | 158 | // set_speed(engine, engine->original_speed); 159 | 160 | reg_update_ex(reg, context->registers->GENERIC_I2C_PIN_SELECTION, (struct reg_fields[]){ 161 | /* 162 | GPIO pin selection to use for SCL, if 163 | GENERIC_I2C_SCL_PIN_SEL == 164 | GENERIC_I2C_SDA_PIN_SEL => disable pin selectin. 165 | 166 | TODO: Where do these values come from and are they 167 | specific to asic types? 168 | */ 169 | PIN_FIELDS(context, GENERIC_I2C_SCL_PIN_SEL, 0), 170 | PIN_FIELDS(context, GENERIC_I2C_SDA_PIN_SEL, 0), 171 | }, 2); 172 | 173 | reg_update_ex(reg, context->registers->GENERIC_I2C_CONTROL, (struct reg_fields[]){ 174 | /* 175 | Reset the controller 176 | */ 177 | PIN_FIELDS(context, GENERIC_I2C_ENABLE, 0), 178 | PIN_FIELDS(context, GENERIC_I2C_SOFT_RESET, 1), 179 | }, 2); 180 | 181 | reg_update_ex(reg, context->registers->GENERIC_I2C_CONTROL, (struct reg_fields[]){ 182 | /* 183 | Clear the reset flag 184 | */ 185 | PIN_FIELDS(context, GENERIC_I2C_SOFT_RESET, 0), 186 | }, 1); 187 | 188 | mutex_unlock(&context->mutex); 189 | } 190 | 191 | 192 | static bool process_transaction ( 193 | const struct aura_i2c_context *context, 194 | struct aura_i2c_transaction *request 195 | ){ 196 | struct aura_reg_service *reg = context->reg_service; 197 | uint32_t length = request->length; 198 | uint8_t *buffer = request->data; 199 | uint32_t value = 0; 200 | 201 | /* 202 | Configure the transaction register 203 | */ 204 | reg_update_ex(reg, context->registers->GENERIC_I2C_TRANSACTION, (struct reg_fields[]){ 205 | /* 206 | Read/write indicator for second transaction - set to 0 for 207 | write, 1 for read. This bit only controls DC_I2C behaviour - 208 | the R/W bit in the transaction is programmed into the I2C 209 | buffer as the LSB of the address byte. 210 | 0=WRITE 211 | 1=READ 212 | MASK == 0x1 213 | */ 214 | PIN_FIELDS(context, GENERIC_I2C_RW, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)), 215 | /* 216 | Determines whether the current transfer will stop if a NACK 217 | is received during the transaction (current transaction 218 | always stops). 219 | 0=STOP CURRENT TRANSACTION, GO TO NEXT 220 | TRANSACTION 221 | 1=STOP ALL TRANSACTIONS, SEND STOP BIT 222 | MASK == 0x100 223 | */ 224 | PIN_FIELDS(context, GENERIC_I2C_STOP_ON_NACK, 1), 225 | /* 226 | Determines whether hardware will send an ACK after the 227 | last byte on a read in the second transaction. 228 | 0=Send NACK 229 | 1=Send ACK 230 | MASK == 0x200 231 | */ 232 | PIN_FIELDS(context, GENERIC_I2C_ACK_ON_READ, 0), 233 | /* 234 | Determines whether a start bit will be sent before the 235 | second transaction 236 | 0=NO START 237 | 1=START 238 | MASK == 0x1000 239 | */ 240 | PIN_FIELDS(context, GENERIC_I2C_START, 1), 241 | /* 242 | Determines whether a stop bit will be sent after the second 243 | transaction 244 | 0=NO STOP 245 | 1=STOP 246 | MASK == 0x2000 247 | */ 248 | PIN_FIELDS(context, GENERIC_I2C_STOP, true ? 1 : 0), 249 | /* 250 | Byte count for the transaction (excluding the first byte, 251 | which is usually the address). 252 | MASK == 0xf0000 253 | */ 254 | PIN_FIELDS(context, GENERIC_I2C_COUNT, length), 255 | }, 6); 256 | 257 | /* Write the I2C address and I2C data 258 | * into the hardware circular buffer, one byte per entry. 259 | * As an example, the 7-bit I2C slave address for CRT monitor 260 | * for reading DDC/EDID information is 0b1010001. 261 | * For an I2C send operation, the LSB must be programmed to 0; 262 | * for I2C receive operation, the LSB must be programmed to 1. 263 | * 264 | */ 265 | value = reg_set_ex(reg, context->registers->GENERIC_I2C_DATA, 0, (struct reg_fields[]){ 266 | /* 267 | Select whether buffer access will be a read or write. For 268 | writes, address auto-increments on write to DC_I2C_DATA. 269 | For reads, address auto-increments on reads to 270 | GENERIC_I2C_DATA. 271 | 0=Write 272 | 1=Read 273 | MASK == 0x1 274 | */ 275 | PIN_FIELDS(context, GENERIC_I2C_DATA_RW, false), 276 | /* 277 | Use to fill or read the generic I2C buffer 278 | MASK == 0xff00 279 | */ 280 | PIN_FIELDS(context, GENERIC_I2C_DATA, request->address), 281 | /* 282 | Use to set index into I2C buffer for next read or current 283 | write, or to read index of current read or next write. Writable 284 | only when GENERIC_I2C_INDEX_WRITE=1. 285 | MASK == 0xf0000 286 | */ 287 | PIN_FIELDS(context, GENERIC_I2C_INDEX, 0), 288 | /* 289 | To write index field, set this bit to 1 while writing 290 | GENERIC_I2C_DATA 291 | MASK == 0x80000000 292 | */ 293 | PIN_FIELDS(context, GENERIC_I2C_INDEX_WRITE, 1), 294 | }, 4); 295 | 296 | if (!(request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)) { 297 | // TODO this should auto increment 298 | uint8_t index = 1; 299 | while (length) { 300 | reg_set_ex(reg, context->registers->GENERIC_I2C_DATA, 0, (struct reg_fields[]){ 301 | PIN_FIELDS(context, GENERIC_I2C_INDEX, index), 302 | PIN_FIELDS(context, GENERIC_I2C_DATA, *buffer++), 303 | }, 2); 304 | 305 | ++index; 306 | --length; 307 | } 308 | } 309 | 310 | return true; 311 | } 312 | 313 | static void execute_transaction ( 314 | const struct aura_i2c_context *context 315 | ){ 316 | struct aura_reg_service *reg = context->reg_service; 317 | 318 | reg_update_ex(reg, context->registers->GENERIC_I2C_CONTROL, (struct reg_fields[]){ 319 | /* 320 | Write 1 to start I2C transfer 321 | */ 322 | PIN_FIELDS(context, GENERIC_I2C_GO, 1), 323 | }, 1); 324 | } 325 | 326 | static void process_reply ( 327 | struct aura_i2c_context *context, 328 | struct aura_i2c_payload *reply 329 | ){ 330 | struct aura_reg_service *reg = context->reg_service; 331 | uint32_t length = reply->length; 332 | uint8_t *buffer = reply->data; 333 | uint8_t index = 1; 334 | struct reg_fields data[] = { 335 | PIN_FIELDS(context, GENERIC_I2C_INDEX, 1), 336 | PIN_FIELDS(context, GENERIC_I2C_DATA, 0) 337 | }; 338 | 339 | // AURA_DBG("process_reply"); 340 | 341 | reg_set_ex(reg, context->registers->GENERIC_I2C_DATA, 0, (struct reg_fields[]){ 342 | /* 343 | Select whether buffer access will be a read or write. For 344 | writes, address auto-increments on write to DC_I2C_DATA. 345 | For reads, address auto-increments on reads to 346 | DC_I2C_DATA. 347 | 0=Write 348 | 1=Read 349 | */ 350 | PIN_FIELDS(context, GENERIC_I2C_DATA_RW, 1), 351 | /* 352 | Use to set index into I2C buffer for next read or current 353 | write, or to read index of current read or next write. Writable 354 | only when GENERIC_I2C_INDEX_WRITE=1. 355 | MASK == 0xf0000 356 | 357 | Note, the byte at index 0 is the slave_address 358 | */ 359 | PIN_FIELDS(context, GENERIC_I2C_INDEX, 1), 360 | /* 361 | To write index field, set this bit to 1 while writing 362 | GENERIC_I2C_DATA 363 | MASK == 0x80000000 364 | */ 365 | PIN_FIELDS(context, GENERIC_I2C_INDEX_WRITE, 1), 366 | }, 3); 367 | 368 | /* 369 | NOTE: Some controllers, this IR3567B in particular, will repeat the 370 | first byte when trying to read multiple. 371 | */ 372 | while (length) { 373 | data[0].value = ++index; 374 | /* 375 | The register buffer auto increments. To get its current index 376 | use DC_I2C_INDEX above 377 | */ 378 | reg_get_ex(reg, context->registers->GENERIC_I2C_DATA, data, 2); 379 | *buffer++ = data[1].value; 380 | 381 | --length; 382 | } 383 | 384 | // AURA_DBG("Reading %d bytes: 0x%02x", reply->length, reply->data[0]); 385 | 386 | clear_ack(context); 387 | } 388 | 389 | static enum aura_i2c_result get_channel_status ( 390 | const struct aura_i2c_context *context 391 | ){ 392 | struct aura_reg_service *reg = context->reg_service; 393 | struct reg_fields status = PIN_FIELDS(context, GENERIC_I2C_STATUS, 0); 394 | uint32_t value = reg_get_ex(reg, context->registers->GENERIC_I2C_STATUS, &status, 1); 395 | 396 | if (status.value || value == 0) { 397 | // AURA_DBG("I2C_CHANNEL_OPERATION_ENGINE_BUSY"); 398 | return I2C_CHANNEL_OPERATION_ENGINE_BUSY; 399 | } 400 | 401 | if (value & context->masks->GENERIC_I2C_STOPPED_ON_NACK) { 402 | // AURA_DBG("I2C_CHANNEL_OPERATION_NO_RESPONSE"); 403 | return I2C_CHANNEL_OPERATION_NO_RESPONSE; 404 | } 405 | 406 | if (value & context->masks->GENERIC_I2C_TIMEOUT) { 407 | // AURA_DBG("I2C_CHANNEL_OPERATION_TIMEOUT"); 408 | return I2C_CHANNEL_OPERATION_TIMEOUT; 409 | } 410 | 411 | if (value & context->masks->GENERIC_I2C_ABORTED) { 412 | // AURA_DBG("I2C_CHANNEL_OPERATION_FAILED"); 413 | return I2C_CHANNEL_OPERATION_FAILED; 414 | } 415 | 416 | if (value & context->masks->GENERIC_I2C_DONE) { 417 | // AURA_DBG("I2C_CHANNEL_OPERATION_SUCCEEDED"); 418 | return I2C_CHANNEL_OPERATION_SUCCEEDED; 419 | } 420 | 421 | if (value & context->masks->GENERIC_I2C_NACK) { 422 | // AURA_DBG("I2C_CHANNEL_OPERATION_NO_RESPONSE"); 423 | return I2C_CHANNEL_OPERATION_NO_RESPONSE; 424 | } 425 | 426 | return I2C_CHANNEL_OPERATION_SUCCEEDED; 427 | } 428 | 429 | enum aura_i2c_result poll_engine ( 430 | struct aura_i2c_context *context 431 | ){ 432 | enum aura_i2c_result result; 433 | uint32_t timeout = context->timeout_interval; 434 | 435 | do { 436 | result = get_channel_status(context); 437 | if (result != I2C_CHANNEL_OPERATION_ENGINE_BUSY) 438 | break; 439 | 440 | udelay(context->timeout_delay); 441 | } while (timeout--); 442 | 443 | clear_ack(context); 444 | 445 | return timeout != 0 ? result : I2C_CHANNEL_OPERATION_TIMEOUT; 446 | } 447 | 448 | 449 | static void submit_transaction ( 450 | struct aura_i2c_context *context, 451 | struct aura_i2c_transaction *request 452 | ){ 453 | request->status = I2C_CHANNEL_OPERATION_SUCCEEDED; 454 | 455 | if (!process_transaction(context, request)) { 456 | AURA_DBG("Failed to process transaction"); 457 | return; 458 | } 459 | 460 | execute_transaction(context); 461 | } 462 | 463 | static bool submit_payload ( 464 | struct aura_i2c_context *context, 465 | struct aura_i2c_payload *payload, 466 | bool middle_of_transaction 467 | ){ 468 | struct aura_i2c_transaction request; 469 | enum aura_i2c_result operation_result; 470 | // uint32_t transaction_timeout; 471 | 472 | if (!payload->write) { 473 | request.action = middle_of_transaction ? 474 | DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT : 475 | DCE_I2C_TRANSACTION_ACTION_I2C_READ; 476 | } else { 477 | request.action = middle_of_transaction ? 478 | DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT : 479 | DCE_I2C_TRANSACTION_ACTION_I2C_WRITE; 480 | } 481 | 482 | request.address = (uint8_t) ((payload->address << 1) | !payload->write); 483 | request.length = payload->length; 484 | request.data = payload->data; 485 | 486 | /* obtain timeout value before submitting request */ 487 | // transaction_timeout = calculate_timeout(engine, payload->length + 1); 488 | 489 | submit_transaction(context, &request); 490 | 491 | if ((request.status == I2C_CHANNEL_OPERATION_FAILED) || (request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY)) 492 | return false; 493 | 494 | /* wait until transaction proceed */ 495 | operation_result = poll_engine(context); 496 | 497 | /* update transaction status */ 498 | if (operation_result == I2C_CHANNEL_OPERATION_SUCCEEDED) { 499 | if (!(payload->write)) 500 | process_reply(context, payload); 501 | 502 | return true; 503 | } 504 | 505 | return false; 506 | } 507 | 508 | 509 | static int aura_gpu_i2c_xfer ( 510 | struct i2c_adapter *i2c_adapter, 511 | struct i2c_msg *msgs, 512 | int num 513 | ){ 514 | struct aura_i2c_context *context = i2c_get_adapdata(i2c_adapter); 515 | struct aura_i2c_payload payload; 516 | bool mot, result = true; 517 | int i; 518 | 519 | if (IS_NULL(context)) 520 | return -EIO; 521 | 522 | open_engine(context); 523 | 524 | // for (i = 0; i < num; i++) { 525 | // if (msgs[i].flags & I2C_M_RD) { 526 | // AURA_DBG("Raw message: rw = 'r', addr = %x, flags = %x, len = %d", 527 | // msgs[i].addr, 528 | // msgs[i].flags, 529 | // msgs[i].len 530 | // ); 531 | // } else { 532 | // AURA_DBG("Raw message: rw = 'w', addr = %x, flags = %x, len = %d, data = %x", 533 | // msgs[i].addr, 534 | // msgs[i].flags, 535 | // msgs[i].len, 536 | // msgs[i].buf[0] 537 | // ); 538 | // } 539 | // } 540 | 541 | /* Detect bus probe */ 542 | // if (num == 1 && msgs[0].len == 0) { 543 | // payload. 544 | // } 545 | 546 | for (i = 0; i < num; i++) { 547 | mot = (i != num - 1); 548 | payload.write = !(msgs[i].flags & I2C_M_RD); 549 | payload.address = msgs[i].addr; 550 | payload.length = msgs[i].len; 551 | payload.data = msgs[i].buf; 552 | 553 | if (!submit_payload(context, &payload, mot)) { 554 | result = false; 555 | break; 556 | } 557 | } 558 | 559 | close_engine(context); 560 | 561 | return result ? num : -EIO; 562 | } 563 | 564 | static u32 aura_gpu_i2c_func ( 565 | struct i2c_adapter *adap 566 | ){ 567 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 568 | } 569 | 570 | static const struct i2c_algorithm aura_gpu_i2c_algo = { 571 | .master_xfer = aura_gpu_i2c_xfer, 572 | .functionality = aura_gpu_i2c_func, 573 | }; 574 | 575 | 576 | static const struct asic_context* aura_gpu_i2c_get_ddc_context ( 577 | enum aura_asic_type asic_type 578 | ){ 579 | switch (asic_type) { 580 | case CHIP_POLARIS10: 581 | case CHIP_POLARIS11: 582 | case CHIP_POLARIS12: 583 | case CHIP_VEGAM: 584 | return &asic_context_polaris; 585 | case CHIP_VEGA10: 586 | case CHIP_VEGA12: 587 | case CHIP_VEGA20: 588 | /* 589 | * FIXME - 590 | * Vega cards do not currently work 591 | */ 592 | return &asic_context_vega; 593 | case CHIP_NAVI10: 594 | /* 595 | TODO - 596 | The GENERIC_I2C_ masks and shifts are not present in the AMDGPU 597 | sources. Test if they are the same across asics and place their 598 | definitions in gpu-registers.h 599 | */ 600 | return &asic_context_navi; 601 | default: 602 | return NULL; 603 | } 604 | } 605 | 606 | static struct aura_i2c_context* aura_gpu_i2c_context_create ( 607 | struct pci_dev *pci_dev, 608 | enum aura_asic_type asic_type 609 | ){ 610 | struct aura_reg_service *registry; 611 | struct aura_i2c_context *context; 612 | const struct asic_context *ddc_context; 613 | error_t err; 614 | 615 | ddc_context = aura_gpu_i2c_get_ddc_context(asic_type); 616 | if (!ddc_context) 617 | return ERR_PTR(-ENODEV); 618 | 619 | context = kzalloc(sizeof(*context), GFP_KERNEL); 620 | if (!context) 621 | return ERR_PTR(-ENOMEM); 622 | 623 | registry = aura_gpu_reg_create(pci_dev); 624 | if (IS_ERR(registry)) { 625 | err = PTR_ERR(registry); 626 | goto error_free_context; 627 | } 628 | 629 | mutex_init(&context->mutex); 630 | context->asic_type = asic_type; 631 | context->reg_service = registry; 632 | 633 | context->registers = ddc_context->i2c_registers; 634 | context->masks = ddc_context->i2c_masks; 635 | context->shifts = ddc_context->i2c_shifts; 636 | 637 | context->original_speed = 50; 638 | context->default_speed = 50; 639 | context->timeout_delay = GPU_I2C_TIMEOUT_DELAY; 640 | context->timeout_interval = GPU_I2C_TIMEOUT_INTERVAL; 641 | 642 | context->i2c_adapter.owner = THIS_MODULE; 643 | context->i2c_adapter.class = I2C_CLASS_DDC; 644 | context->i2c_adapter.algo = &aura_gpu_i2c_algo; 645 | 646 | snprintf(context->i2c_adapter.name, sizeof(context->i2c_adapter.name), "AURA GPU adapter"); 647 | i2c_set_adapdata(&context->i2c_adapter, context); 648 | 649 | // TODO - Do we really need to expose this? 650 | err = i2c_add_adapter(&context->i2c_adapter); 651 | if (err) 652 | goto error_free_registry; 653 | 654 | return context; 655 | 656 | error_free_registry: 657 | aura_gpu_reg_destroy(registry); 658 | error_free_context: 659 | kfree(context); 660 | 661 | return ERR_PTR(err); 662 | } 663 | 664 | 665 | void gpu_adapter_destroy ( 666 | struct i2c_adapter *i2c_adapter 667 | ){ 668 | struct aura_i2c_context *context = context_from_adapter(i2c_adapter); 669 | 670 | if (IS_NULL(i2c_adapter)) 671 | return; 672 | 673 | i2c_del_adapter(&context->i2c_adapter); 674 | aura_gpu_reg_destroy(context->reg_service); 675 | kfree(context); 676 | } 677 | 678 | struct i2c_adapter *gpu_adapter_create ( 679 | void 680 | ){ 681 | struct pci_dev *pci_dev; 682 | const struct pci_device_id *match; 683 | struct aura_i2c_context *context = NULL; 684 | 685 | /* Handle the case of mixed GPU types */ 686 | pci_dev = NULL; 687 | 688 | while (NULL != (pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev))) { 689 | match = pci_match_id(pciidlist, pci_dev); 690 | if (match) { 691 | AURA_DBG("Detected AURA capable GPU %x:%x", pci_dev->subsystem_vendor, pci_dev->subsystem_device); 692 | 693 | context = aura_gpu_i2c_context_create(pci_dev, match->driver_data); 694 | if (!IS_ERR_OR_NULL(context)) 695 | return &context->i2c_adapter; 696 | } 697 | } 698 | 699 | return NULL; 700 | } 701 | 702 | int gpu_adapters_create ( 703 | struct i2c_adapter *i2c_adapters[2], 704 | uint8_t count 705 | ){ 706 | struct pci_dev *pci_dev; 707 | const struct pci_device_id *match; 708 | struct aura_i2c_context *context = NULL; 709 | error_t err; 710 | int found; 711 | 712 | if (IS_NULL(i2c_adapters) || IS_FALSE(count == 2)) 713 | return -EINVAL; 714 | 715 | /* Handle the case of mixed GPU types */ 716 | pci_dev = NULL; 717 | found = 0; 718 | 719 | while (NULL != (pci_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev))) { 720 | match = pci_match_id(pciidlist, pci_dev); 721 | if (match) { 722 | AURA_DBG("Detected AURA capable GPU %x:%x", pci_dev->subsystem_vendor, pci_dev->subsystem_device); 723 | 724 | context = aura_gpu_i2c_context_create(pci_dev, match->driver_data); 725 | if (IS_ERR(context)) { 726 | err = CLEAR_ERR(context); 727 | goto error_free; 728 | } 729 | 730 | if (context) { 731 | i2c_adapters[found++] = &context->i2c_adapter; 732 | if (found >= count) 733 | break; 734 | } 735 | } 736 | } 737 | 738 | return found; 739 | 740 | error_free: 741 | while (found > 0) { 742 | found--; 743 | gpu_adapter_destroy(i2c_adapters[found]); 744 | } 745 | 746 | return err; 747 | } 748 | -------------------------------------------------------------------------------- /aura-gpu-i2c.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_AURA_GPU_I2C_H 3 | #define _UAPI_AURA_GPU_I2C_H 4 | 5 | #include "aura-gpu-reg.h" 6 | #include "asic/asic-types.h" 7 | 8 | struct i2c_adapter *gpu_adapter_create ( 9 | void 10 | ); 11 | 12 | int gpu_adapters_create ( 13 | struct i2c_adapter *i2c_adapters[2], 14 | uint8_t count 15 | ); 16 | 17 | void gpu_adapter_destroy ( 18 | struct i2c_adapter *i2c_adapter 19 | ); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /aura-gpu-reg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | #include 3 | 4 | #include "debug.h" 5 | #include "aura-gpu-reg.h" 6 | 7 | #define mmMM_INDEX 0x0000 8 | #define mmMM_DATA 0x0001 9 | 10 | struct aura_reg_context { 11 | struct aura_reg_service service; 12 | spinlock_t lock; 13 | resource_size_t base; 14 | resource_size_t size; 15 | void __iomem *data; 16 | uint32_t last_index; 17 | struct pci_dev *pci_dev; 18 | }; 19 | 20 | #if defined(DEBUG_GPU_REG) 21 | 22 | static const char *reg_name(uint32_t reg) 23 | { 24 | /* NOTE - These names are only valid for polaris cards */ 25 | switch (reg) { 26 | case 0x16f4: 27 | return "GENERIC_I2C_CONTROL "; 28 | case 0x16f5: 29 | return "GENERIC_I2C_INTERRUPT_CONTROL "; 30 | case 0x16f6: 31 | return "GENERIC_I2C_STATUS "; 32 | case 0x16f7: 33 | return "GENERIC_I2C_SPEED "; 34 | case 0x16f8: 35 | return "GENERIC_I2C_SETUP "; 36 | case 0x16f9: 37 | return "GENERIC_I2C_TRANSACTION "; 38 | case 0x16fa: 39 | return "GENERIC_I2C_DATA "; 40 | case 0x16fb: 41 | return "GENERIC_I2C_PIN_SELECTION "; 42 | case 0x16fc: 43 | return "GENERIC_I2C_PIN_DEBUG "; 44 | } 45 | 46 | return ""; 47 | } 48 | 49 | #define log_reg_read(_reg, _value)\ 50 | AURA_DBG("Reg Read: %s %x", reg_name(_reg), _value); 51 | 52 | #define log_reg_write(_reg, _value)\ 53 | AURA_DBG("Reg Write: %s %x", reg_name(_reg), _value); 54 | 55 | #else 56 | 57 | #define log_reg_read(_reg, _value) 58 | #define log_reg_write(_reg, _value) 59 | 60 | #endif 61 | 62 | int32_t reg_read ( 63 | struct aura_reg_service *service, 64 | uint32_t reg 65 | ){ 66 | struct aura_reg_context *ctx = container_of(service, struct aura_reg_context, service); 67 | uint32_t ret; 68 | 69 | if (unlikely(service == NULL)) { 70 | AURA_ERR("mmio has not been configured"); 71 | return 0; 72 | } 73 | 74 | if ((reg * 4) < ctx->size) 75 | ret = readl(((void __iomem *)ctx->data) + (reg * 4)); 76 | else { 77 | unsigned long flags; 78 | 79 | spin_lock_irqsave(&ctx->lock, flags); 80 | writel((reg * 4), ((void __iomem *)ctx->data) + (mmMM_INDEX * 4)); 81 | ret = readl(((void __iomem *)ctx->data) + (mmMM_DATA * 4)); 82 | spin_unlock_irqrestore(&ctx->lock, flags); 83 | } 84 | 85 | log_reg_read(reg, ret); 86 | 87 | return ret; 88 | } 89 | 90 | void reg_write ( 91 | struct aura_reg_service *service, 92 | uint32_t reg, 93 | uint32_t value 94 | ){ 95 | struct aura_reg_context *ctx = container_of(service, struct aura_reg_context, service); 96 | 97 | if (unlikely(service == NULL)) { 98 | AURA_ERR("mmio has not been configured"); 99 | return; 100 | } 101 | 102 | log_reg_write(reg, value); 103 | 104 | if ((reg * 4) < ctx->size) 105 | writel(value, ((void __iomem *)ctx->data) + (reg * 4)); 106 | else { 107 | unsigned long flags; 108 | 109 | spin_lock_irqsave(&ctx->lock, flags); 110 | writel((reg * 4), ((void __iomem *)ctx->data) + (mmMM_INDEX * 4)); 111 | writel(value, ((void __iomem *)ctx->data) + (mmMM_DATA * 4)); 112 | spin_unlock_irqrestore(&ctx->lock, flags); 113 | } 114 | } 115 | 116 | uint32_t reg_field_get_value_ex( 117 | const struct reg_fields *field 118 | ){ 119 | return (field->value & field->mask) >> field->shift; 120 | } 121 | 122 | uint32_t reg_field_set_value_ex( 123 | uint32_t value, 124 | struct reg_fields *field 125 | ){ 126 | field->value = (value & ~field->mask) | (field->mask & (field->value << field->shift)); 127 | 128 | return field->value; 129 | } 130 | 131 | uint32_t reg_update_ex( 132 | struct aura_reg_service *service, 133 | uint32_t addr, 134 | const struct reg_fields *fields, 135 | ssize_t cnt 136 | ){ 137 | uint32_t ret; 138 | uint32_t value = 0, mask = 0; 139 | 140 | WARN_ON(cnt <= 0); 141 | 142 | while (cnt) { 143 | value = (value & ~fields->mask) | (fields->mask & (fields->value << fields->shift)); 144 | mask = mask | fields->mask; 145 | fields++; 146 | cnt--; 147 | } 148 | 149 | /* mmio write directly */ 150 | ret = reg_read(service, addr); 151 | ret = (ret & ~mask) | value; 152 | 153 | reg_write(service, addr, ret); 154 | 155 | return ret; 156 | } 157 | 158 | uint32_t reg_set_ex( 159 | struct aura_reg_service *service, 160 | uint32_t addr, 161 | uint32_t init, 162 | const struct reg_fields *fields, 163 | ssize_t cnt 164 | ){ 165 | uint32_t value = 0, mask = 0; 166 | 167 | WARN_ON(cnt == 0); 168 | 169 | while (cnt) { 170 | value = (value & ~fields->mask) | (fields->mask & (fields->value << fields->shift)); 171 | mask = mask | fields->mask; 172 | fields++; 173 | cnt--; 174 | } 175 | 176 | /* mmio write directly */ 177 | init = (init & ~mask) | value; 178 | reg_write(service, addr, init); 179 | 180 | return init; 181 | } 182 | 183 | uint32_t reg_get_ex( 184 | struct aura_reg_service *service, 185 | uint32_t addr, 186 | struct reg_fields *fields, 187 | ssize_t cnt 188 | ){ 189 | uint32_t value, i; 190 | 191 | WARN_ON(cnt <= 0); 192 | 193 | value = reg_read(service, addr); 194 | 195 | for (i = 0; i < cnt; i++) { 196 | fields[i].value = (value & fields[i].mask) >> fields[i].shift; 197 | } 198 | 199 | return value; 200 | } 201 | 202 | uint32_t reg_get_value( 203 | struct aura_reg_service *service, 204 | uint32_t addr, 205 | struct reg_fields *fields, 206 | uint32_t *value 207 | ){ 208 | uint32_t ret = reg_get_ex(service, addr, fields, 1); 209 | 210 | BUG_ON(value == NULL); 211 | 212 | *value = fields->value; 213 | return ret; 214 | } 215 | 216 | uint32_t reg_update_seq_ex( 217 | struct aura_reg_service *service, 218 | uint32_t addr, 219 | const struct reg_fields *fields, 220 | ssize_t cnt 221 | ){ 222 | uint32_t value, i; 223 | 224 | WARN_ON(cnt <= 1); 225 | 226 | value = reg_update_ex(service, addr, fields, 1); 227 | 228 | for (i = 1; i <= cnt; i++) { 229 | value = reg_set_ex(service, addr, value, &fields[i], 1); 230 | } 231 | 232 | return value; 233 | } 234 | 235 | void reg_wait_ex( 236 | struct aura_reg_service *service, 237 | uint32_t addr, 238 | struct reg_fields *field, 239 | uint32_t attempts, 240 | uint32_t timeout 241 | ){ 242 | uint32_t value; 243 | 244 | WARN_ON(timeout * attempts <= 200); 245 | 246 | do { 247 | value = reg_read(service, addr); 248 | value = (value & field->mask) >> field->shift; 249 | 250 | if (value == field->value) { 251 | return; 252 | } 253 | 254 | if (timeout >= 1000) 255 | msleep(timeout / 1000); 256 | else if (timeout > 0) 257 | udelay(timeout); 258 | 259 | attempts--; 260 | } while(attempts); 261 | } 262 | 263 | struct aura_reg_service *aura_gpu_reg_create( 264 | struct pci_dev *pci_dev 265 | ){ 266 | struct aura_reg_context *ctx; 267 | error_t err = -ENOMEM; 268 | 269 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 270 | if (!ctx) 271 | goto error; 272 | 273 | spin_lock_init(&ctx->lock); 274 | 275 | ctx->pci_dev = pci_dev; 276 | ctx->base = pci_resource_start(pci_dev, 5); 277 | ctx->size = pci_resource_len(pci_dev, 5); 278 | ctx->data = ioremap(ctx->base, ctx->size); 279 | 280 | if (ctx->data == NULL) 281 | goto error_free_context; 282 | 283 | AURA_DBG("Mapped ports at base=0x%16llx, size=0x%16llx to %p", ctx->base, ctx->size, ctx->data); 284 | 285 | return &ctx->service; 286 | 287 | error_free_context: 288 | kfree(ctx); 289 | error: 290 | return ERR_PTR(err); 291 | } 292 | 293 | void aura_gpu_reg_destroy ( 294 | struct aura_reg_service *service 295 | ){ 296 | struct aura_reg_context *ctx = container_of(service, struct aura_reg_context, service); 297 | 298 | if (WARN_ON(service == NULL)) 299 | return; 300 | 301 | AURA_DBG("Unmapping mm data"); 302 | iounmap(ctx->data); 303 | kfree(ctx); 304 | } 305 | -------------------------------------------------------------------------------- /aura-gpu-reg.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_AURA_GPU_REGISTRY_H 3 | #define _UAPI_AURA_GPU_REGISTRY_H 4 | 5 | #include 6 | #include 7 | #include "include/types.h" 8 | 9 | struct reg_fields { 10 | uint32_t mask; 11 | uint32_t value; 12 | uint8_t shift; 13 | }; 14 | 15 | struct aura_reg_service { 16 | void *private; 17 | }; 18 | 19 | #define PIN_FIELDS(_pin, _field, _value) \ 20 | { \ 21 | .mask = _pin->masks->_field, \ 22 | .shift = _pin->shifts->_field, \ 23 | .value = _value \ 24 | } 25 | 26 | int32_t reg_read ( 27 | struct aura_reg_service *service, 28 | uint32_t reg 29 | ); 30 | void reg_write ( 31 | struct aura_reg_service *service, 32 | uint32_t reg, 33 | uint32_t value 34 | ); 35 | 36 | uint32_t reg_get_field_value( 37 | const struct reg_fields *field 38 | ); 39 | uint32_t reg_set_field_value( 40 | uint32_t value, 41 | struct reg_fields *field 42 | ); 43 | 44 | #define reg_field_get_value_ex reg_get_field_value 45 | #define reg_field_set_value_ex reg_set_field_value 46 | 47 | #define reg_field_get_value(value, reg, field) \ 48 | reg_field_get_value_ex((struct reg_fields[]){ \ 49 | REG_FIELD(reg, field, value), \ 50 | }) 51 | #define reg_field_set_value(set_value, value, reg, field) \ 52 | reg_field_set_value_ex(set_value, (struct reg_fields[]){ \ 53 | REG_FIELD(reg, field, value), \ 54 | }) 55 | 56 | uint32_t reg_update_ex( 57 | struct aura_reg_service *service, 58 | uint32_t addr, 59 | const struct reg_fields *fields, 60 | ssize_t cnt 61 | ); 62 | uint32_t reg_update_seq_ex( 63 | struct aura_reg_service *service, 64 | uint32_t addr, 65 | const struct reg_fields *fields, 66 | ssize_t cnt 67 | ); 68 | uint32_t reg_set_ex( 69 | struct aura_reg_service *service, 70 | uint32_t addr, 71 | uint32_t init, 72 | const struct reg_fields *fields, 73 | ssize_t cnt 74 | ); 75 | uint32_t reg_get_ex( 76 | struct aura_reg_service *service, 77 | uint32_t addr, 78 | struct reg_fields *fields, 79 | ssize_t cnt 80 | ); 81 | uint32_t reg_get_value( 82 | struct aura_reg_service *service, 83 | uint32_t addr, 84 | struct reg_fields *fields, 85 | uint32_t *value 86 | ); 87 | void reg_wait_ex( 88 | struct aura_reg_service *service, 89 | uint32_t addr, 90 | struct reg_fields *field, 91 | uint32_t attempts, 92 | uint32_t timeout 93 | ); 94 | 95 | struct aura_reg_service *aura_gpu_reg_create( 96 | struct pci_dev *pci_dev 97 | ); 98 | void aura_gpu_reg_destroy ( 99 | struct aura_reg_service *service 100 | ); 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /debug.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_AURA_DEBUG_H 3 | #define _UAPI_AURA_DEBUG_H 4 | 5 | #define LIGHTS_MODULE "aura" 6 | 7 | #include "include/debug.h" 8 | 9 | #define AURA_DBG LIGHTS_DBG 10 | #define AURA_INFO LIGHTS_INFO 11 | #define AURA_ERR LIGHTS_ERR 12 | #define AURA_WARN LIGHTS_WARN 13 | #define AURA_TRACE LIGHTS_TRACE 14 | #define AURA_DUMP LIGHTS_DUMP 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/debug.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_INCLUDE_DEBUG_H 3 | #define _UAPI_INCLUDE_DEBUG_H 4 | 5 | #include "err.h" 6 | #include "types.h" 7 | 8 | #ifndef LIGHTS_MODULE 9 | #error LIGHTS_MODULE must be defined 10 | #endif 11 | 12 | #define __LIGHTS_PREFIX "lights " LIGHTS_MODULE ": " 13 | 14 | #ifdef DEBUG 15 | #define _IS_NULL(_1) WARN(NULL == (_1), __LIGHTS_PREFIX "arg '%s' is NULL", #_1) 16 | #define _EXEC_1(X,_1) X(_1) 17 | #define _EXEC_2(X,_1,_2) (X(_1) || X(_2)) 18 | #define _EXEC_3(X,_1,_2,_3) (X(_1) || X(_2) || X(_3)) 19 | #define _EXEC_4(X,_1,_2,_3,_4) (X(_1) || X(_2) || X(_3) || X(_4)) 20 | #define _EXEC(_0, _1, _2, _3, _4, N, ...) N 21 | #define IS_NULL(...) \ 22 | _EXEC("dummy", ##__VA_ARGS__, _EXEC_4, _EXEC_3, _EXEC_2, _EXEC_1)(_IS_NULL, ##__VA_ARGS__) 23 | #define IS_TRUE(_1) WARN(_1, __LIGHTS_PREFIX "expr '%s' is TRUE", #_1) 24 | #define IS_FALSE(_1) WARN(!(_1), "lights hw: expr '%s' is FALSE", #_1) 25 | #else 26 | #define IS_NULL(...) 27 | #define IS_TRUE(_1) 28 | #define IS_FALSE(_1) 29 | #endif 30 | 31 | #define LIGHTS_ERR(_fmt, ...)({ \ 32 | pr_err(__LIGHTS_PREFIX "[%s:%d] " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ 33 | }) 34 | 35 | #define LIGHTS_WARN(_fmt, ...) ({ \ 36 | pr_warn(__LIGHTS_PREFIX "[%s:%d] " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ 37 | }) 38 | 39 | #define LIGHTS_DBG(_fmt, ...) ({ \ 40 | pr_debug(__LIGHTS_PREFIX "[%s:%d] " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ 41 | }) 42 | 43 | #define LIGHTS_INFO(_fmt, ...) ({ \ 44 | pr_info(__LIGHTS_PREFIX "[%s:%d] " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ 45 | }) 46 | 47 | #define LIGHTS_TRACE(_fmt, ...) ({ \ 48 | pr_debug(__LIGHTS_PREFIX "[%s:%d] " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ 49 | }) 50 | 51 | #define LIGHTS_DUMP(p) ({ \ 52 | print_hex_dump_bytes(__LIGHTS_PREFIX "\n", DUMP_PREFIX_NONE, (p), sizeof(*(p)) ); \ 53 | }) 54 | 55 | #define ERR_NAME strerr 56 | 57 | #define CLEAR_ERR(_var) ({ \ 58 | error_t ___err = PTR_ERR(_var); \ 59 | if (___err == 0) ___err = -ENOMEM; \ 60 | LIGHTS_DBG("Failed to assign '%s': %s", #_var, ERR_NAME(___err)); \ 61 | _var = NULL; \ 62 | ___err; \ 63 | }) 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/err.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_INCLUDE_ERR_H 3 | #define _UAPI_INCLUDE_ERR_H 4 | 5 | #include 6 | 7 | #define UNKNOWN_ERR "Error Unknown" 8 | 9 | static const char *err_names[] = { 10 | [0] = "EOK", /* Not an Error */ 11 | [1] = "EPERM", /* Operation not permitted */ 12 | [2] = "ENOENT", /* No such file or directory */ 13 | [3] = "ESRCH", /* No such process */ 14 | [4] = "EINTR", /* Interrupted system call */ 15 | [5] = "EIO", /* I/O error */ 16 | [6] = "ENXIO", /* No such device or address */ 17 | [7] = "E2BIG", /* Argument list too long */ 18 | [8] = "ENOEXEC", /* Exec format error */ 19 | [9] = "EBADF", /* Bad file number */ 20 | [10] = "ECHILD", /* No child processes */ 21 | [11] = "EAGAIN", /* Try again */ 22 | [12] = "ENOMEM", /* Out of memory */ 23 | [13] = "EACCES", /* Permission denied */ 24 | [14] = "EFAULT", /* Bad address */ 25 | [15] = "ENOTBLK", /* Block device required */ 26 | [16] = "EBUSY", /* Device or resource busy */ 27 | [17] = "EEXIST", /* File exists */ 28 | [18] = "EXDEV", /* Cross-device link */ 29 | [19] = "ENODEV", /* No such device */ 30 | [20] = "ENOTDIR", /* Not a directory */ 31 | [21] = "EISDIR", /* Is a directory */ 32 | [22] = "EINVAL", /* Invalid argument */ 33 | [23] = "ENFILE", /* File table overflow */ 34 | [24] = "EMFILE", /* Too many open files */ 35 | [25] = "ENOTTY", /* Not a typewriter */ 36 | [26] = "ETXTBSY", /* Text file busy */ 37 | [27] = "EFBIG", /* File too large */ 38 | [28] = "ENOSPC", /* No space left on device */ 39 | [29] = "ESPIPE", /* Illegal seek */ 40 | [30] = "EROFS", /* Read-only file system */ 41 | [31] = "EMLINK", /* Too many links */ 42 | [32] = "EPIPE", /* Broken pipe */ 43 | [33] = "EDOM", /* Math argument out of domain of func */ 44 | [34] = "ERANGE", /* Math result not representable */ 45 | [35] = "EDEADLK", /* Resource deadlock would occur */ 46 | [36] = "ENAMETOOLONG", /* File name too long */ 47 | [37] = "ENOLCK", /* No record locks available */ 48 | 49 | /* 50 | * This error code is special: arch syscall entry code will return 51 | * -ENOSYS if users try to call a syscall that doesn't exist. To keep 52 | * failures of syscalls that really do exist distinguishable from 53 | * failures due to attempts to use a nonexistent syscall, syscall 54 | * implementations should refrain from returning -ENOSYS. 55 | */ 56 | [38] = "ENOSYS", /* Invalid system call number */ 57 | 58 | [39] = "ENOTEMPTY", /* Directory not empty */ 59 | [40] = "ELOOP", /* Too many symbolic links encountered */ 60 | [42] = "ENOMSG", /* No message of desired type */ 61 | [43] = "EIDRM", /* Identifier removed */ 62 | [44] = "ECHRNG", /* Channel number out of range */ 63 | [45] = "EL2NSYNC", /* Level 2 not synchronized */ 64 | [46] = "EL3HLT", /* Level 3 halted */ 65 | [47] = "EL3RST", /* Level 3 reset */ 66 | [48] = "ELNRNG", /* Link number out of range */ 67 | [49] = "EUNATCH", /* Protocol driver not attached */ 68 | [50] = "ENOCSI", /* No CSI structure available */ 69 | [51] = "EL2HLT", /* Level 2 halted */ 70 | [52] = "EBADE", /* Invalid exchange */ 71 | [53] = "EBADR", /* Invalid request descriptor */ 72 | [54] = "EXFULL", /* Exchange full */ 73 | [55] = "ENOANO", /* No anode */ 74 | [56] = "EBADRQC", /* Invalid request code */ 75 | [57] = "EBADSLT", /* Invalid slot */ 76 | 77 | [59] = "EBFONT", /* Bad font file format */ 78 | [60] = "ENOSTR", /* Device not a stream */ 79 | [61] = "ENODATA", /* No data available */ 80 | [62] = "ETIME", /* Timer expired */ 81 | [63] = "ENOSR", /* Out of streams resources */ 82 | [64] = "ENONET", /* Machine is not on the network */ 83 | [65] = "ENOPKG", /* Package not installed */ 84 | [66] = "EREMOTE", /* Object is remote */ 85 | [67] = "ENOLINK", /* Link has been severed */ 86 | [68] = "EADV", /* Advertise error */ 87 | [69] = "ESRMNT", /* Srmount error */ 88 | [70] = "ECOMM", /* Communication error on send */ 89 | [71] = "EPROTO", /* Protocol error */ 90 | [72] = "EMULTIHOP", /* Multihop attempted */ 91 | [73] = "EDOTDOT", /* RFS specific error */ 92 | [74] = "EBADMSG", /* Not a data message */ 93 | [75] = "EOVERFLOW", /* Value too large for defined data type */ 94 | [76] = "ENOTUNIQ", /* Name not unique on network */ 95 | [77] = "EBADFD", /* File descriptor in bad state */ 96 | [78] = "EREMCHG", /* Remote address changed */ 97 | [79] = "ELIBACC", /* Can not access a needed shared library */ 98 | [80] = "ELIBBAD", /* Accessing a corrupted shared library */ 99 | [81] = "ELIBSCN", /* .lib section in a.out corrupted */ 100 | [82] = "ELIBMAX", /* Attempting to link in too many shared libraries */ 101 | [83] = "ELIBEXEC", /* Cannot exec a shared library directly */ 102 | [84] = "EILSEQ", /* Illegal byte sequence */ 103 | [85] = "ERESTART", /* Interrupted system call should be restarted */ 104 | [86] = "ESTRPIPE", /* Streams pipe error */ 105 | [87] = "EUSERS", /* Too many users */ 106 | [88] = "ENOTSOCK", /* Socket operation on non-socket */ 107 | [89] = "EDESTADDRREQ", /* Destination address required */ 108 | [90] = "EMSGSIZE", /* Message too long */ 109 | [91] = "EPROTOTYPE", /* Protocol wrong type for socket */ 110 | [92] = "ENOPROTOOPT", /* Protocol not available */ 111 | [93] = "EPROTONOSUPPORT", /* Protocol not supported */ 112 | [94] = "ESOCKTNOSUPPORT", /* Socket type not supported */ 113 | [95] = "EOPNOTSUPP", /* Operation not supported on transport endpoint */ 114 | [96] = "EPFNOSUPPORT", /* Protocol family not supported */ 115 | [97] = "EAFNOSUPPORT", /* Address family not supported by protocol */ 116 | [98] = "EADDRINUSE", /* Address already in use */ 117 | [99] = "EADDRNOTAVAIL", /* Cannot assign requested address */ 118 | [100] = "ENETDOWN", /* Network is down */ 119 | [101] = "ENETUNREACH", /* Network is unreachable */ 120 | [102] = "ENETRESET", /* Network dropped connection because of reset */ 121 | [103] = "ECONNABORTED", /* Software caused connection abort */ 122 | [104] = "ECONNRESET", /* Connection reset by peer */ 123 | [105] = "ENOBUFS", /* No buffer space available */ 124 | [106] = "EISCONN", /* Transport endpoint is already connected */ 125 | [107] = "ENOTCONN", /* Transport endpoint is not connected */ 126 | [108] = "ESHUTDOWN", /* Cannot send after transport endpoint shutdown */ 127 | [109] = "ETOOMANYREFS", /* Too many references: cannot splice */ 128 | [110] = "ETIMEDOUT", /* Connection timed out */ 129 | [111] = "ECONNREFUSED", /* Connection refused */ 130 | [112] = "EHOSTDOWN", /* Host is down */ 131 | [113] = "EHOSTUNREACH", /* No route to host */ 132 | [114] = "EALREADY", /* Operation already in progress */ 133 | [115] = "EINPROGRESS", /* Operation now in progress */ 134 | [116] = "ESTALE", /* Stale file handle */ 135 | [117] = "EUCLEAN", /* Structure needs cleaning */ 136 | [118] = "ENOTNAM", /* Not a XENIX named type file */ 137 | [119] = "ENAVAIL", /* No XENIX semaphores available */ 138 | [120] = "EISNAM", /* Is a named type file */ 139 | [121] = "EREMOTEIO", /* Remote I/O error */ 140 | [122] = "EDQUOT", /* Quota exceeded */ 141 | 142 | [123] = "ENOMEDIUM", /* No medium found */ 143 | [124] = "EMEDIUMTYPE", /* Wrong medium type */ 144 | [125] = "ECANCELED", /* Operation Canceled */ 145 | [126] = "ENOKEY", /* Required key not available */ 146 | [127] = "EKEYEXPIRED", /* Key has expired */ 147 | [128] = "EKEYREVOKED", /* Key has been revoked */ 148 | [129] = "EKEYREJECTED", /* Key was rejected by service */ 149 | 150 | /* for robust mutexes */ 151 | [130] = "EOWNERDEAD", /* Owner died */ 152 | [131] = "ENOTRECOVERABLE", /* State not recoverable */ 153 | [132] = "ERFKILL", /* Operation not possible due to RF-kill */ 154 | [133] = "EHWPOISON" /* Memory page has hardware error */ 155 | }; 156 | 157 | static inline const char *strerr (int err) { 158 | unsigned num = abs(err); 159 | const char* name = NULL; 160 | 161 | if (num < ARRAY_SIZE(err_names)) 162 | name = err_names[num]; 163 | 164 | return name ? name : UNKNOWN_ERR; 165 | } 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /include/quirks.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_INCLUDE_QUIRKS_H 3 | #define _UAPI_INCLUDE_QUIRKS_H 4 | 5 | #include 6 | 7 | /* 8 | This file contains a few fixes for changes between kernels. 9 | */ 10 | 11 | #if (LINUX_VERSION_CODE <= KERNEL_VERSION(5,1,18)) 12 | static inline void list_swap(struct list_head *entry1, struct list_head *entry2) 13 | { 14 | struct list_head *pos = entry2->prev; 15 | 16 | list_del(entry2); 17 | list_replace(entry1, entry2); 18 | if (pos == entry1) 19 | pos = entry2; 20 | list_add(entry1, pos); 21 | } 22 | #endif 23 | 24 | #if (LINUX_VERSION_CODE <= KERNEL_VERSION(5,0,0)) 25 | #define is_user_memory(_ptr, _size) access_ok(VERIFY_READ, _ptr, _size) 26 | #else 27 | #define is_user_memory access_ok 28 | #endif 29 | 30 | #ifndef EXPORT_SYMBOL_NS_GPL 31 | #define EXPORT_SYMBOL_NS_GPL(sym, ns) EXPORT_SYMBOL_GPL(sym) 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_INCLUDE_TYPES_H 3 | #define _UAPI_INCLUDE_TYPES_H 4 | 5 | #ifndef ERROR_TYPE 6 | typedef int error_t; 7 | #define ERROR_TYPE error_t 8 | #endif 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | #include 3 | #include 4 | 5 | #include "debug.h" 6 | #include "aura-gpu-hw.h" 7 | 8 | static struct i2c_adapter *adapter = NULL; 9 | 10 | static int __init aura_module_init ( 11 | void 12 | ){ 13 | adapter = aura_i2c_bios_create(); 14 | if (IS_ERR_OR_NULL(adapter)) 15 | CLEAR_ERR(adapter); 16 | 17 | return 0; 18 | } 19 | 20 | static void __exit aura_module_exit ( 21 | void 22 | ){ 23 | if (adapter) 24 | aura_i2c_bios_destroy(adapter); 25 | } 26 | 27 | module_init(aura_module_init); 28 | module_exit(aura_module_exit); 29 | 30 | 31 | MODULE_AUTHOR("Owen Parry "); 32 | MODULE_DESCRIPTION("ASUS AURA SMBus driver"); 33 | MODULE_LICENSE("GPL"); 34 | -------------------------------------------------------------------------------- /pci_ids.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _UAPI_AURA_PCI_DEV_I2C_H 3 | #define _UAPI_AURA_PCI_DEV_I2C_H 4 | 5 | #include 6 | #include "asic/asic-types.h" 7 | 8 | /* 9 | AMD devices require an i2c adapter to be created, 10 | NVIDIA devices already have the adapter loaded. 11 | */ 12 | static const struct pci_device_id pciidlist[] = { 13 | {0x1002, 0x67df, 0x1043, 0x0517, 0, 0, CHIP_POLARIS10}, // RX580 (Strix) 14 | {0x1002, 0x687F, 0x1043, 0x0555, 0, 0, CHIP_VEGA10}, // Vega 56 (Strix) 15 | // {0x1002, 0x731f, 0x1043, 0x04e2, 0, 0, CHIP_NAVI10}, // RX5700XT (Strix) 16 | {0, 0, 0}, 17 | }; 18 | 19 | #endif 20 | --------------------------------------------------------------------------------