📄 hw_ser8260.c
字号:
/* * $QNXLicenseC: * Copyright 2007, QNX Software Systems. * * Licensed under the Apache License, Version 2.0 (the "License"). You * may not reproduce, modify or distribute this software except in * compliance with the License. You may obtain a copy of the License * at: http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * * This file may contain contributions from others, either as * contributors under the License or as licensors under other terms. * Please review this entire file for other proprietary rights or license * notices, as well as the QNX Development Suite License Guide at * http://licensing.qnx.com/license-guide/ for other information. * $ */#include "startup.h"#include <ppc/8260cpu.h>#include <ppc/8260cpm.h>// Receive buffer 8 * (16 bytes), send buffer 8 * (16 bytes)#undef PPC8260_IMMR#define PPC8260_IMMR(reg,size) (*(volatile uint##size##_t *) (pv_immr_base_addr+PPC8260_IMMR_OFF_##reg))static uintptr_t pv_immr_base_addr;paddr32_t ptrTxBD[6];paddr32_t ptrRxBD[6];extern uint32_t ppc8260_brgclk;static voidparse_line(unsigned channel, const char *line, unsigned *baud, unsigned *clk, unsigned *div, paddr_t *base) {// base holds the 8260 chanel no, like smc1, scc2, etc. if(*line != '.' && *line != '\0') { if(line[1] == 'm' || line[1] == 'M') { line += 3; dbg_device[channel].base = *line++ - '1'; } else if(line[1] == 'c' || line[1] == 'C') { line += 3; dbg_device[channel].base = *line++ - '1' + 2; } if(*line == '^') dbg_device[channel].shift = strtoul(line+1, (char **)&line, 0); } if(*line == '.') ++line; if(*line != '.' && *line != '\0') *baud = strtoul(line, (char **)&line, 0); if(*line == '.') ++line; if(*line != '.' && *line != '\0') *clk = strtoul(line, (char **)&line, 0); if(*line == '.') ++line; if(*line != '.' && *line != '\0') *div = strtoul(line, (char **)&line, 0); if(*line == '.') ++line; if(*line != '.' && *line != '\0') *base = strtopaddr(line, (char **)&line, 0);}static void sendCommand8260(uint32_t com, PPC8260CPM_CH_NUM port) { static uint32_t chanelID[6] = {PPC8260CPM_CPCR_PAGE_SMC1 | PPC8260CPM_CPCR_SBC_SMC1, PPC8260CPM_CPCR_PAGE_SMC2 | PPC8260CPM_CPCR_SBC_SMC2, PPC8260CPM_CPCR_PAGE_SCC1 | PPC8260CPM_CPCR_SBC_SCC1, PPC8260CPM_CPCR_PAGE_SCC2 | PPC8260CPM_CPCR_SBC_SCC2, PPC8260CPM_CPCR_PAGE_SCC3 | PPC8260CPM_CPCR_SBC_SCC3, PPC8260CPM_CPCR_PAGE_SCC4 | PPC8260CPM_CPCR_SBC_SCC4, }; // wait for the command register available do { } while(PPC8260_IMMR(CPCR, 32) & PPC8260CPM_CPCR_FLG); // send command PPC8260_IMMR(CPCR, 32) = com | chanelID[port] | PPC8260CPM_CPCR_FLG;}static void setBuffers8260 (PPC8260CPM_CH_NUM port, uint32_t base) { int i; paddr32_t addrDPRAM, ptr; uintptr_t v2p_off = pv_immr_base_addr - (immr_paddr + cpm_offset); static const paddr32_t addrBDT[6] = { PPC8260CPM_DPRAM_BDT_SMC1, PPC8260CPM_DPRAM_BDT_SMC2, PPC8260CPM_DPRAM_BDT_SCC1, PPC8260CPM_DPRAM_BDT_SCC2, PPC8260CPM_DPRAM_BDT_SCC3, PPC8260CPM_DPRAM_BDT_SCC4, }; static const paddr32_t addrDBuf[6] = { PPC8260CPM_DPRAM_DBUF_SMC1, PPC8260CPM_DPRAM_DBUF_SMC2, PPC8260CPM_DPRAM_DBUF_SCC1, PPC8260CPM_DPRAM_DBUF_SCC2, PPC8260CPM_DPRAM_DBUF_SCC3, PPC8260CPM_DPRAM_DBUF_SCC4 }; static const paddr32_t baseParaRAM[6] = { PPC8260CPM_DPRAM_PARA_SMC1, PPC8260CPM_DPRAM_PARA_SMC2, PPC8260CPM_DPRAMPARA_SCC1, PPC8260CPM_DPRAMPARA_SCC2, PPC8260CPM_DPRAMPARA_SCC3, PPC8260CPM_DPRAMPARA_SCC4 }; paddr32_t dbuf, bdt; addrDPRAM = (paddr32_t) &PPC8260_IMMR(DPRAM1, 8); if(base<0xffff) { bdt = base; dbuf = base + 0x100; } else { bdt = addrBDT[port]; dbuf = addrDBuf[port]; } // relocate receive buffer ptrRxBD[port] = ptr = addrDPRAM + bdt; out32(ptr, ptr + PPC8260CPM_BD_SIZE - addrDPRAM); ptr += PPC8260CPM_BD_SIZE; for(i=0; i<PPC8260CPM_UART_DBNUM_D; i++) { out16(ptr, PPC8260CPM_UART_RXBD_E); ptr += 2; out16(ptr, 0); ptr += 2; out32(ptr, addrDPRAM-v2p_off+dbuf+PPC8260CPM_UART_DBSIZE_D*i); ptr += 4; } ptr -= PPC8260CPM_BD_SIZE; out16(ptr, PPC8260CPM_UART_RXBD_W|PPC8260CPM_UART_RXBD_E); out16(addrDPRAM+baseParaRAM[port]+PPC8260CPM_PARARAM_SCCSMC_RBASE, ptrRxBD[port]-addrDPRAM + PPC8260CPM_BD_SIZE); // start of real BDT is 8 bytes after // set receive buffer size out16(addrDPRAM+baseParaRAM[port]+PPC8260CPM_PARARAM_SCCSMC_MRBLR, 1); if(port > PPC8260_SMC2) { // Init Control Characters table for SCCs out16(addrDPRAM+baseParaRAM[port]+PPC8260CPM_PARARAM_SCCUART_CHAR1, PPC8260CPM_PARARAM_SCCUART_CHAR_E); // set MAX_IDL out16(addrDPRAM+baseParaRAM[port]+PPC8260CPM_PARARAM_SCCUART_MAXIDL, 10); } // relocate transmit buffer ptrTxBD[port] = ptr = addrDPRAM+bdt+PPC8260CPM_BD_SIZE*(1+PPC8260CPM_UART_DBNUM_D); out32(ptr, ptr + PPC8260CPM_BD_SIZE - addrDPRAM); ptr += PPC8260CPM_BD_SIZE; for(i=0; i<PPC8260CPM_UART_DBNUM_D; i++) { out32(ptr, 0); ptr += 4; out32(ptr, addrDPRAM-v2p_off+dbuf+PPC8260CPM_UART_DBSIZE_D*(PPC8260CPM_UART_DBNUM_D+i)); ptr += 4; } ptr -= PPC8260CPM_BD_SIZE; out16(ptr, PPC8260CPM_UART_TXBD_W); out16(addrDPRAM + baseParaRAM[port] + PPC8260CPM_PARARAM_SCCSMC_TBASE, ptrTxBD[port]-addrDPRAM + PPC8260CPM_BD_SIZE);// start of real BDT is 8 bytes after out16(addrDPRAM + baseParaRAM[port] + PPC8260CPM_PARARAM_SCCSMC_RFCR, 0x1010);}voidinit_8260cpm(unsigned channel, const char *init, const char *defaults) { unsigned baud; unsigned div; unsigned clk; unsigned cnt, value, brg; paddr_t base = 0xffffffff; PPC8260CPM_CH_NUM port; pv_immr_base_addr = startup_io_map(0x14000, immr_paddr + cpm_offset); parse_line(channel, defaults, &baud, &clk, &div, &base); parse_line(channel, init, &baud, &clk, &div, &base); port = dbg_device[channel].base; brg = dbg_device[channel].shift; /* * For PQ2FADS board and 8266ADS-PCI board, the BRG clock will * change depending which MODCK switches are set. So, setting * the BRG clock to a fixed value in startup won't work in all * cases. If 0 is specified in the debug_devices struct as the * clock frequency, then determine the correct BRG clock by * reading the PLL multiplication factor. */ if (clk == 0) clk = ppc8260_brgclk; switch(port) { case PPC8260_SMC1: // config GPIO PPC8260_IMMR(PSORD, 32) &= ~(_ONEBIT32B(8) | _ONEBIT32B(9)); PPC8260_IMMR(PDIRD, 32) |= _ONEBIT32B(9); PPC8260_IMMR(PDIRD, 32) &= ~_ONEBIT32B(8); PPC8260_IMMR(PPARD, 32) |= _ONEBIT32B(9) | _ONEBIT32B(8); // select mode and clock source PPC8260_IMMR(CMXSMR, 8) &= ~(PPC8260CPM_CMXSMR_SMC1); if(brg == 6) { PPC8260_IMMR(CMXSMR, 8) |= PPC8260CPM_CMXSMR_SMC1CS_BRG7; } else { PPC8260_IMMR(CMXSMR, 8) |= PPC8260CPM_CMXSMR_SMC1CS_BRG1; brg = 0; } // program for line paras: 8bits, no parity, & disable send/receive PPC8260_IMMR(SMCMR1, 16) = PPC8260CPM_SMCMR_UART_SMUART | PPC8260CPM_SMCMR_UART_CLEN(8,0,1); // disable int PPC8260_IMMR(SMCM1, 8) = 0; // init parameter base ptr out16((paddr32_t)&PPC8260_IMMR(DPRAM1, 8) + PPC8260CPM_DPRAMPARA_SMC1_BASE, PPC8260CPM_DPRAM_PARA_SMC1); break; case PPC8260_SMC2: // config GPIO PPC8260_IMMR(PSORA, 32) &= ~(_ONEBIT32B(8) | _ONEBIT32B(9)); PPC8260_IMMR(PDIRA, 32) |= _ONEBIT32B(9); PPC8260_IMMR(PDIRA, 32) &= ~_ONEBIT32B(8); PPC8260_IMMR(PPARA, 32) |= _ONEBIT32B(8) | _ONEBIT32B(9); // select mode and clock source PPC8260_IMMR(CMXSMR, 8) &= ~(PPC8260CPM_CMXSMR_SMC2); if(brg == 7) { PPC8260_IMMR(CMXSMR, 8) |= PPC8260CPM_CMXSMR_SMC2CS_BRG8; } else { PPC8260_IMMR(CMXSMR, 8) |= PPC8260CPM_CMXSMR_SMC2CS_BRG2; brg = 1; } // program for line paras: 8bits, no parity, & disable send/receive PPC8260_IMMR(SMCMR2, 16) = PPC8260CPM_SMCMR_UART_SMUART | PPC8260CPM_SMCMR_UART_CLEN(8,0,1); // disable int PPC8260_IMMR(SMCM2, 8) = 0; // init parameter base ptr out16((paddr32_t)&PPC8260_IMMR(DPRAM1, 8) + PPC8260CPM_DPRAMPARA_SMC2_BASE, PPC8260CPM_DPRAM_PARA_SMC2); break; case PPC8260_SCC1: // config GPIO PPC8260_IMMR(PSORD, 32) &= ~_ONEBIT32B(31); PPC8260_IMMR(PSORD, 32) |= _ONEBIT32B(30); PPC8260_IMMR(PDIRD, 32) |= _ONEBIT32B(30); PPC8260_IMMR(PDIRD, 32) &= ~_ONEBIT32B(31); PPC8260_IMMR(PPARD, 32) |= _ONEBIT32B(30) | _ONEBIT32B(31); // select mode and clock source PPC8260_IMMR(CMXSCR, 32) &= ~(PPC8260CPM_CMXSCR_GR1 | PPC8260CPM_CMXSCR_SC1 | PPC8260CPM_CMXSCR_RS1CS_M | PPC8260CPM_CMXSCR_TS1CS_M); if(brg <= 3) { PPC8260_IMMR(CMXSCR, 32) |= PPC8260CPM_CMXSCR_RS1CS(brg) | PPC8260CPM_CMXSCR_TS1CS(brg); } else { PPC8260_IMMR(CMXSCR, 32) |= PPC8260CPM_CMXSCR_RS1CS_BRG1 | PPC8260CPM_CMXSCR_TS1CS_BRG1; brg = 0; } // config GSMR PPC8260_IMMR(GSMR_H1, 32) = PPC8260CPM_GSMR_H_RFW; PPC8260_IMMR(GSMR_L1, 32) = PPC8260CPM_GSMR_L_TDCR16 | PPC8260CPM_GSMR_L_RDCR16 | PPC8260CPM_GSMR_L_MODEUART; // program for line paras: 8bits, no parity PPC8260_IMMR(PSMR1, 16) = PPC8260CPM_SCCMR_UART_CL8; // disable int PPC8260_IMMR(SCCM1, 16) = 0; break; case PPC8260_SCC2: // config GPIO PPC8260_IMMR(PSORD, 32) &= ~(_ONEBIT32B(27) | _ONEBIT32B(28)); PPC8260_IMMR(PDIRD, 32) |= _ONEBIT32B(27); PPC8260_IMMR(PDIRD, 32) &= ~_ONEBIT32B(28); PPC8260_IMMR(PPARD, 32) |= _ONEBIT32B(27) | _ONEBIT32B(28); // select mode and clock source PPC8260_IMMR(CMXSCR, 32) &= ~(PPC8260CPM_CMXSCR_GR2 | PPC8260CPM_CMXSCR_SC2 | PPC8260CPM_CMXSCR_RS2CS_M | PPC8260CPM_CMXSCR_TS2CS_M); if(brg <= 3) { PPC8260_IMMR(CMXSCR, 32) |= PPC8260CPM_CMXSCR_RS2CS(brg) | PPC8260CPM_CMXSCR_TS2CS(brg); } else { PPC8260_IMMR(CMXSCR, 32) |= PPC8260CPM_CMXSCR_RS2CS_BRG1 | PPC8260CPM_CMXSCR_TS2CS_BRG1; brg = 0; } // config GSMR PPC8260_IMMR(GSMR_H2, 32) = PPC8260CPM_GSMR_H_RFW; PPC8260_IMMR(GSMR_L2, 32) = PPC8260CPM_GSMR_L_TDCR16 | PPC8260CPM_GSMR_L_RDCR16 | PPC8260CPM_GSMR_L_MODEUART; // program for line paras: 8bits, no parity PPC8260_IMMR(PSMR2, 16) = PPC8260CPM_SCCMR_UART_CL8; // disable int PPC8260_IMMR(SCCM2, 16) = 0; break; case PPC8260_SCC3: // config GPIO PPC8260_IMMR(PSORD, 32) &= ~(_ONEBIT32B(24) | _ONEBIT32B(25)); PPC8260_IMMR(PDIRD, 32) |= _ONEBIT32B(24); PPC8260_IMMR(PDIRD, 32) &= ~_ONEBIT32B(25); PPC8260_IMMR(PPARD, 32) |= _ONEBIT32B(24) | _ONEBIT32B(25); // select mode and clock source PPC8260_IMMR(CMXSCR, 32) &= ~(PPC8260CPM_CMXSCR_GR3 | PPC8260CPM_CMXSCR_SC3 | PPC8260CPM_CMXSCR_RS3CS_M | PPC8260CPM_CMXSCR_TS3CS_M); if(brg <= 3) { PPC8260_IMMR(CMXSCR, 32) |= PPC8260CPM_CMXSCR_RS3CS(brg) | PPC8260CPM_CMXSCR_TS3CS(brg); } else { PPC8260_IMMR(CMXSCR, 32) |= PPC8260CPM_CMXSCR_RS3CS_BRG1 | PPC8260CPM_CMXSCR_TS3CS_BRG1; brg = 0; } // config GSMR PPC8260_IMMR(GSMR_H3, 32) = PPC8260CPM_GSMR_H_RFW; PPC8260_IMMR(GSMR_L3, 32) = PPC8260CPM_GSMR_L_TDCR16 | PPC8260CPM_GSMR_L_RDCR16 | PPC8260CPM_GSMR_L_MODEUART; // program for line paras: 8bits, no parity PPC8260_IMMR(PSMR3, 16) = PPC8260CPM_SCCMR_UART_CL8; // disable int PPC8260_IMMR(SCCM3, 16) = 0; break; case PPC8260_SCC4: // config GPIO PPC8260_IMMR(PSORD, 32) &= ~(_ONEBIT32B(21) | _ONEBIT32B(22)); PPC8260_IMMR(PDIRD, 32) |= _ONEBIT32B(21); PPC8260_IMMR(PDIRD, 32) &= ~_ONEBIT32B(22); PPC8260_IMMR(PPARD, 32) |= _ONEBIT32B(21) | _ONEBIT32B(22); // select mode and clock source PPC8260_IMMR(CMXSCR, 32) &= ~(PPC8260CPM_CMXSCR_GR4 | PPC8260CPM_CMXSCR_SC4 | PPC8260CPM_CMXSCR_RS4CS_M | PPC8260CPM_CMXSCR_TS4CS_M); if(brg <= 3) { PPC8260_IMMR(CMXSCR, 32) |= PPC8260CPM_CMXSCR_RS4CS(brg) | PPC8260CPM_CMXSCR_TS4CS(brg); } else { PPC8260_IMMR(CMXSCR, 32) |= PPC8260CPM_CMXSCR_RS4CS_BRG1 | PPC8260CPM_CMXSCR_TS4CS_BRG1; brg = 0; } // config GSMR PPC8260_IMMR(GSMR_H4, 32) = PPC8260CPM_GSMR_H_RFW; PPC8260_IMMR(GSMR_L4, 32) = PPC8260CPM_GSMR_L_TDCR16 | PPC8260CPM_GSMR_L_RDCR16 | PPC8260CPM_GSMR_L_MODEUART; // program for line paras: 8bits, no parity PPC8260_IMMR(PSMR4, 16) = PPC8260CPM_SCCMR_UART_CL8; // disable int PPC8260_IMMR(SCCM4, 16) = 0; break; default: break; } // set baudrate cnt = (clk + ((baud * div) >> 1)) / (baud * div); // accurately if(cnt < PPC8260CPM_BRG_MAXCNT) { value = PPC8260CPM_BRG_EN | PPC8260CPM_BRG_EXTC(0) | PPC8260CPM_BRG_CD((--cnt)); } else { cnt = (cnt + 8) / 16; value = PPC8260CPM_BRG_EN | PPC8260CPM_BRG_EXTC(0) | PPC8260CPM_BRG_CD((--cnt)) | PPC8260CPM_BRG_DIV16; } switch(brg) { case 0: PPC8260_IMMR(BRGC1, 32) = value; break; case 1: PPC8260_IMMR(BRGC2, 32) = value; break; case 2: PPC8260_IMMR(BRGC3, 32) = value; break; case 3: PPC8260_IMMR(BRGC4, 32) = value; break; case 4: PPC8260_IMMR(BRGC5, 32) = value; break; case 5: PPC8260_IMMR(BRGC6, 32) = value; break; case 6: PPC8260_IMMR(BRGC7, 32) = value; break; case 7: PPC8260_IMMR(BRGC8, 32) = value; break; default: break; } // set Rx TX buffers setBuffers8260(port, base); // reset para sendCommand8260(PPC8260CPM_CPCR_INITRXTX, port); // enable send/receive switch(port) { case PPC8260_SMC1: PPC8260_IMMR(SMCMR1, 16) |= (PPC8260CPM_SMCMR_UART_TEN | PPC8260CPM_SMCMR_UART_REN); break; case PPC8260_SMC2: PPC8260_IMMR(SMCMR2, 16) |= (PPC8260CPM_SMCMR_UART_TEN | PPC8260CPM_SMCMR_UART_REN); break; case PPC8260_SCC1: PPC8260_IMMR(GSMR_L1, 32) |= (PPC8260CPM_GSMR_L_ENR | PPC8260CPM_GSMR_L_ENT); break; case PPC8260_SCC2: PPC8260_IMMR(GSMR_L2, 32) |= (PPC8260CPM_GSMR_L_ENR | PPC8260CPM_GSMR_L_ENT); break; case PPC8260_SCC3: PPC8260_IMMR(GSMR_L3, 32) |= (PPC8260CPM_GSMR_L_ENR | PPC8260CPM_GSMR_L_ENT); break; case PPC8260_SCC4: PPC8260_IMMR(GSMR_L4, 32) |= (PPC8260CPM_GSMR_L_ENR | PPC8260CPM_GSMR_L_ENT); break; default: break; } startup_io_unmap(pv_immr_base_addr);}voidput_8260cpm(int c) { PPC8260CPM_CH_NUM port; paddr32_t addrDPRAM; paddr32_t ptr; uintptr_t v2p_off; pv_immr_base_addr = startup_io_map(0x14000, immr_paddr + cpm_offset); v2p_off = pv_immr_base_addr - (immr_paddr + cpm_offset); port = (PPC8260CPM_CH_NUM) dbg_device[0].base; addrDPRAM = (paddr32_t)&PPC8260_IMMR(DPRAM1, 8); ptr = in32(ptrTxBD[port]) + addrDPRAM; // waiting for the transmit buffer ready do { } while(in16(ptr) & PPC8260CPM_UART_TXBD_R); // next available buffer if(in16(ptr) & PPC8260CPM_UART_TXBD_W) { out32(ptrTxBD[port], ptrTxBD[port] + PPC8260CPM_BD_SIZE - addrDPRAM); } else { out32(ptrTxBD[port], ptr + PPC8260CPM_BD_SIZE - addrDPRAM); } // Write a char to the buffer out8(in32(ptr+PPC8260CPM_BD_POINTER)+v2p_off, c); out16(ptr+PPC8260CPM_BD_COUNT, 1); out16(ptr, in16(ptr) | PPC8260CPM_UART_TXBD_R); startup_io_unmap(pv_immr_base_addr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -